Top 5 Recent Articles
ARTICLES CATEGORIES
- Algorithms (22)
- All (399)
- Biography (1)
- Blog (44)
- Business Requirements (1)
- Commentary (1)
- Conversion (2)
- Customers (2)
- Data Models (1)
- Education (2)
- GeoRaptor (13)
- GPS (1)
- Image Processing (2)
- Import Export (8)
- Licensing (2)
- LiDAR (1)
- Linear Referencing (4)
- Manifold GIS (3)
- Mapping (1)
- MySQL Spatial (7)
- Networking and Routing (including Optimization) (5)
- Open Source (18)
- Oracle Spatial and Locator (194)
- Partitioning (1)
- PostGIS (36)
- Projections (1)
- Published Articles (1)
- qGIS (1)
- Recommendations (1)
- Services (1)
- Software Change Log (1)
- Source Code (37)
- Space Curves (9)
- Spatial Database Functions (109)
- Spatial DB comparison (1)
- Spatial XML Processing (11)
- SQL Server Spatial (92)
- Standards (3)
- Stored Procedure (17)
- Tessellation or Gridding (10)
- Tools (2)
- Topological Relationships (1)
- Training (2)
- Triangulation (2)
qGIS, GEOMETRY_COLUMNS and SQL Server Spatial
Introduction
For a small investment in effort, use of the GEOMETRY_COLUMNS table within a SQL Server Spatial database, will improve the performance of spatial data discovery by qGIS.
Background
The ISO19125 standard – OpenGIS® Implementation Specification for Geographic information – Simple feature access – Part 2: SQL option – provides for the creation and use of the GEOMETRY_COLUMNS metadata table.
The GEOMETRY_COLUMNS table describes the available feature tables and their geometry properties.
Table Definition
The following definition can be used to create the GEOMETRY_COLUMNS table within SQL Server. This definition includes additional columns for qGIS (prefixed with qgis_).
CREATE TABLE [dbo].[geometry_columns] ( [f_table_catalog] [varchar](128) NOT NULL ,[f_table_schema] [varchar](128) NOT NULL ,[f_table_name] [varchar](256) NOT NULL ,[f_geometry_column] [varchar](256) NOT NULL ,[coord_dimension] [int] NOT NULL ,[srid] [int] NOT NULL ,[geometry_type] [varchar](30) NOT NULL ,[qgis_xmin] [float] ,[qgis_ymin] [float] ,[qgis_xmax] [float] ,[qgis_ymax] [float] ,[qgis_pkey] [varchar](128) CONSTRAINT [geometry_columns_pk] PRIMARY KEY CLUSTERED ( [f_table_catalog] ASC ,[f_table_schema] ASC ,[f_table_name] ASC ,[f_geometry_column] ASC ,[geometry_type] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]; GO
Populating the Table
The above table can be populated manually, or it can be populated via use of one of the following functions which are available within the TSQL functions downloadable from this website via a small donation.
- STPopulateGeometryColumns — Procedure that adds rows to the GEOMETRY_COLUMNS table for the specified schema/tables
- STAddGeometryColumn — Procedure that adds metadata rows for a single geometry column to GEOMETRY_COLUMNS
- STSetGeometryColumnExtent — Procedure that computes spatial extent of table/column and updates entry in GEOMETRY_COLUMNS
STPopulateGeometryColumns calls STAddGeometryColumn and STSetGeometryColumnExtent.
An example of how to call the STPopulateGeometryColumns procedure is as follows.
DROP TABLE dbo.foo; GO CREATE TABLE dbo.foo ( id int Identity not null, geom_type varchar(50), geom geography, constraint foo_pk primary key (id) ); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('POINT(147.111 -32.2222)',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('MULTIPOINT((147.21 -32.22),(147.31 -32.32))',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('LINESTRING(147.1 -32.2, 147.1 -33.2)',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('COMPOUNDCURVE(CIRCULARSTRING(147.0 -31.5, 147.5 -31.0, 148.0 -31.5),(148.0 -31.5, 147.0 -31.5))',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('CIRCULARSTRING(148.0 -32.0,148.51 -31.5,149.0 -32.0)',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('MULTILINESTRING((147.21 -32.2, 147.21 -33.2),(148.21 -33.0,148.22 -33.1))',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('POLYGON((147.0 -31.0,147.5 -31.0,147.5 -30.5,147.0 -30.5,147.0 -31.0))',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('MULTIPOLYGON (((148.0 -33.9,148.9 -33.9,148.9 -33.0,148.0 -33.0,148.0 -33.9)),((149.1 -33.1,149.2 -33.1,149.2 -33.0,149.1 -33.0,149.1 -33.1)))',4326)); INSERT INTO dbo.foo (geom) VALUES (geography::STGeomFromText('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(145.0 -34.5,145.5 -35.0, 146.0 -34.0),(146.0 -34.0, 145.0 -34.5)),(145.6 -34.5,145.6 -34.3,145.8 -34.3,145.8 -34.5,145.6 -34.5))',4326)); UPDATE dbo.foo SET geom_type = geom.STGeometryType(); delete from dbo.geometry_columns where f_table_name = 'foo'; execute dbo.STPopulateGeometryColumns 'dbo', 'foo';
The resultant entries are as follows.
f_table_catalog | f_table_schema | f_table_name | f_geometry_column | coord_dimension | srid | geometry_type | qgis_xmin | qgis_ymin | qgis_xmax | qgis_ymax | qgis_pkey |
---|---|---|---|---|---|---|---|---|---|---|---|
DEVDB | dbo | foo | geom | 2 | 4326 | LINESTRING | 146.999998999853 | -33.2 | 149.000001010149 | -30.999998999969 | id |
DEVDB | dbo | foo | geom | 2 | 4326 | MULTILINESTRING | 147.21 | -33.2 | 148.22 | -32.2 | id |
DEVDB | dbo | foo | geom | 2 | 4326 | MULTIPOINT | 147.21 | -32.32 | 147.31 | -32.22 | id |
DEVDB | dbo | foo | geom | 2 | 4326 | MULTIPOLYGON | 148 | -33.9 | 149.2 | -33 | id |
DEVDB | dbo | foo | geom | 2 | 4326 | POINT | 147.11099705778 | -32.222200644444 | 147.11100294222 | -32.222199355556 | id |
DEVDB | dbo | foo | geom | 2 | 4326 | POLYGON | 144.999998827411 | -35.0059234902795 | 147.5 | -30.5 | id |
NOTE: The STAddGeometryColumn procedure discovers all the Geometry Types within a nominated table/column. Currently the function creates geometry types based on the OGC Geometry Type hierarchy such that LineString/CircularString/CompoundCurve geometries are represented by a single LINESTRING type (similarly for polygons).
This function can be easily modified to create individual types eg CircularString.
qGIS Access
To enable access to this table by qGIS one needs to tick the following entries in the Database Connection dialog:
- Only look in the geometry_columns metadata table.
- Use layer extent from geometry_columns table.
- Use primary key from geometry_columns table.
Once saved and dismissed, pressing Connect on the Data Source Manager dialog will cause qGIS to access the records in the GEOMETRY_COLUMNS table.
NOTE: The performance difference between using GEOMETRY_COLUMNS or querying the SQL Server metadata and individual tables (to extract extent, geometry type etc) can be substantial especially where there are a lot of large tables being accessed. Additionally the performance hit is repeated every time the Connection is refreshed.
The two downsides for using GEOMETRY_COLUMNS are:
- If the spatial extent of the data changes one has to remember to update the GEOMETRY_COLUMNS entry.
- GEOMETRY_COLUMNS entries need to be created and maintained: this is made easier if one uses my TSQL functions for SQL Server.
Conclusion
Use of the GEOMETRY_COLUMNS metadata view is highly recommended, with greatly improved metadata access performance for all qGIS clients connecting to the database.
Creation and maintenance of this table is fairly straightforward with TSQL functions being made available via the shop on this website.
Documentation
- MySQL Spatial General Functions
- Oracle LRS Objects
- Oracle Spatial Exporter (Java + pl/SQL)
- Oracle Spatial Object Functions
- Oracle Spatial Object Functions (Multi Page)
- PostGIS pl/pgSQL Functions
- SC4O Oracle Java Topology Suite (Java + pl/SQL)
- SQL Server Spatial General TSQL Functions
- SQL Server Spatial LRS TSQL Functions