SpatialDB Advisor
|
Current Oracle Spatial Blog Articles • Compute Location from known Lat/Long point using delta easting and northing in miles • SDO_AGGR_SET_UNION • Sorting SDO_GEOMETRY data using the ORDER BY clause of a SELECT statement • Creating linestrings (2002) from points (2001) • Rounding Coordinates or Ordinates in SDO_GEOMETRY • Effects of Sdo_Geometry Ordinate Precision on Performance • Effects of Sdo_Geometry Ordinate Precision on Storage • The Spatial filtering of geometries: The effect of tolerances on relationships • Application of Delaunay Triangulation and Inverse Distance Weighting (IDW) in Oracle for Soils Interpolation • Selecting all SDO_GTYPE values for all tables/sdo_geometry columns in a schema • CENTROID package - Tips for Use • Announcing the Spatial Companion For Oracle (SC4O) • Filtering Rings (Oracle Spatial) • Splitting a polygon using one or more linestrings • isValid, isSimple, Dimension and CoordDim methods for SDO_Geometry • Line Merging or Collecting lines together: ST_LineMerger • ST_RemovePoint for Oracle SDO_Geometry based on Jaspa/JTS • 3D/4D and SRID aware Conversion functions for SDO_Geometry: WKT and EWKT • Topological vs Non-Topological Simplification/Generalization of Aggregated Area Geometies in Oracle • Filtering very short linestrings via bitmap function index • CENTROID For Oracle • Gridding a sdo_geometry line/polygon object (Oracle) • Finding centre and radius of a circular geometry • Constraining geometry type for sdo_geometry column in a table. • CASE Statements and SDO_GEOMETRY • The Power of Constraints and Indexes for Spatial Constraints: stopping duplicate points • SURVEY: The Future of GeoRaptor • Replacement for SDO_GEOM.RELATE - JTS Relate • Changing Oracle Spatial Index Parameters on existing index • Writing Excel Spreadsheets files from within the Oracle database using Java and PL/SQL • Writing xSV (eg csv) files from within the Oracle database using Java and PL/SQL • A simple spike finder for Spatial/Locator • JTS Java class compilation for 11g and above • Random Spatial Search Procedure • Geometry Snapping using JTS in Oracle • Exposing JTS's MinimumBoundingCircle functionality • Exposing JTS's Densifier functionality • Using JTS's Comparison Functions - HausdorffSimilarityMeasure & AreaSimilarityMeasure with SDO_GEOMETRY • Free JTS-based Area/Length Functions • Handy way of systematically fixing polygon geometries with 13349 and other errors • Standalone CENTROID package now available for download • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 4 Processing Geodetic data • Configurable Buffer: JTS and Oracle • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 3 • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 2 • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 1 • Building Lines into Polygons in Oracle Locator / Spatial • Finding Intersection Points between Line and Polygon • SDO2GeoJSON • Free version of sdo_length • Alternative to my SQL based GetNumRings function • External Tables and SDO_Geometry data. • layer_gtype keyword issue when indexing linear data on 11g • String Tokenizer for Oracle • Free Aggregate Method for Concatenating 2D Lines in Oracle Locator 10g • Reducing 5 Vertex Polygon to Optimized Rectangle • Square Buffer • GeoRaptor 3.0 Officially released. • Converting decimal seconds to string • SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT - 13356 Issues • Valid conversion unit values for Oracle sdo_geom.sdo_length() • Removing Steps in Gridded Vector Data - SmoothGrid for Oracle • Oracle Spatial DISJOINT search/filtering • Creating SDO_Geometry from geometric data recorded in the columns of a table • Concave Hull Geometries in Oracle 11gR2 • Projecting SDO_GEOM_METADATA DIMINFO XY ordinates • Instantiating MDSYS.VERTEX_TYPE • New PL/SQL Packages - Rotate oriented point • GeoRaptor Development Team • Fast Refreshing Materialized View Containing SDO_GEOMETRY and SDO_GEOM.SDO_AREA function • Performance of PL/SQL Functions using SQL vs Pure Code • Implementing the BEST VicGrid Projection in Oracle 10gR2 • Making Sdo Geometry Metadata Update Generic Code • ORA-13011 errors when using SDO_GEOM.VALIDATE_LAYER_WITH_CONTEXT() • Extract Polygons from Compound Polygon • Detecting sdo_geometries with compound (3-point Arcs) segments • GEOMETRY_COLUMNS for Oracle Spatial • Convert GML to SDO_Geometry in Oracle 10gR2 • Spatial Sorting of Data via Morton Key • Swapping Ordinates in an SDO_GEOMETRY object • New To_3D Function • Extend (Reduce/Contract/Skrink) Function for Oracle • Loading and Processing GPX 1.1 files using Oracle XMLDB • Loading Spatial Data from an external CSV file in Oracle • Calling the Oracle Spatial shapefile loader from within the Oracle database itself • Converting Google Earth Formatted Longitude/Latitude points to decimal degrees • Implementing SDO_VertexUpdate/ST_VertexUpdate for Oracle • Implementing SDO_RemovePoint/ST_RemovePoint for Oracle • Implementing SDO_AddPoint/ST_AddPoint for Oracle • ESRI ArcSDE Exverted and Inverted Polygons and Oracle Spatial • Funky Fix Ordinates By Formula • Implementing a SetPoint/ST_SetPoint function in Oracle • Implementing an ST_SnapToGrid (PostGIS) function for Oracle Spatial • Generating random point data • Implementing an Affine/ST_Affine function for Oracle Spatial • Implementing a Scale/ST_Scale function for Oracle Spatial • Implementing a Parallel/ST_Parallel function for linestring data for Oracle Spatial • Implementing a Rotate/ST_Rotate function for Oracle Spatial • Limiting table list returned when connecting to Oracle Database using ODBC • ST_Azimuth for Oracle: AKA Cogo.Bearing • Implementing a Translate/ST_Translate/Move function for Oracle Spatial • Elem_Info_Array Processing: An alternative to SDO_UTIL.GetNumRings and querying SDO_ELEM_INFO itself • Minumum Bounding Rectangle (MBR) Object Type for Oracle • How to extract elements from the result of an sdo_intersection of two polygons. • How to restart a database after failed parameter change • Fixing failed spatial indexes after import using data pump • generate_series: an Oracle implementation in light of SQL Design Patterns • Multi-Centroid Shootout • Oracle Spatial Centroid Shootout • On the use of ROLLUP in Oracle SELECT statements • Surrounding Parcels • Spatial Pipelining • Using Oracle's SDO_NN Operator - Some examples • Converting distances and units of measure in Oracle Locator • Split Sdo_Geometry Linestring at a known point • Forcing an Sdo_Geometry object to contain only points, lines or areas • Unpacking USER_SDO_GEOM_METADATA's DIMINFO structure using SQL • Generating multi-points from single point records in Oracle Spatial • Object Tables of Sdo_Geometry • Oracle Locator vs Oracle Spatial: A Reflection on Oracle Licensing of the SDO_GEOM Package • FAST REFRESHing of Oracle Materialized Views containing Sdo_Geometry columns • Australian MGA/AMG Zone Calculation from geographic (longitude/latitude) data • Loading Shapefiles (SHP) into Oracle Spatial • Oracle Spatial Mapping and Map Rendering Performance Tips • The significance of sdo_lb/sdo_ub in USER_SDO_GEOM_METDATA: Do I need it? • Oracle Spatial Forum - Melbourne April 2007 • Layer_GTypes for spatial indexes • Oracle's SQL/MM Compliant Types • Tips and Tricks
|
I have often advocated the use of a spatial sort when loading static spatial data into Oracle (See 1. Spatially sort read-only data. in my article on performance tips). The idea here is to try and place spatial data that is close together in space (called spatial autocorrelation), close together on disk. Then, when the hard-disk’s head goes down on the disk to retrieve one or more records, the head will not have to travel far to retrieve the geographically close data. Imagine you zooming in to a particular area in your GIS. The search will be a minimum bounding rectangle based query that is specifically requesting data that is close together geographically. If disk activity can be minimised by spatial autocorrelation then performance will improve. But really, I had never gotten around to producing a robust solution for use solely within the Oracle database. Until now. Object Relational Databases like Oracle are ideally suited to this task through the SELECT statement’s ORDER BY clause such that we can create a new table and populate it as follows:
(Of course we are assuming that when Oracle creates the table it will use contiguous blocks on disk. This will only be true is the tablespace is new or has been degragmented.) Now, the problem is that a sort order is not defined on an Oracle Sdo_Geometry object such that one could sort as follows:
Oracle’s lack of a sort of any kind based on the SDO_Geometry object is why I have not provided a practical example before now. (Though it is worth noting that PostGIS can sort by geometry with Regina Obe observing that the sort is a btree sort: not rtree as in PostGIS’s CLUSTER ON geometry). The standard way of sorting based on the Oracle RTree is to simply do an SDO_Filter search using the MBR of the whole of the data as follows:
One could also sort simply by X and Y via use of any point in a geometry. Thus, for Oracle point data, this would also work:
Suitability of Sort Of course both the PostGIS “ORDER BY geometry” sort and the Oracle RTree (SDO_Filter…) and XY based sorts will sort the data, but they will do so in strips based on Y and X. What other theory can be used to define a spatial sort function? Space curves There is a body of theory that describes a space-filling curve such as in Z-Order) or Peano (my favourite). These curves, I would assert, when implemented, provide a better method for taking advantage of the spatially autocorrelation that is implicit to spatial data. PostGIS 1.4 has implemented the ST_GeoHash function which I assume is a form of a space curve – see GeoHash Website – but this only for geodetic – longitude/latitude data. Oracle is supposed to have implemented the Z-Order access method. From what I recall this would have been part of the original MultiDimension implementation in the 1990s. Now, the only place I have can find an implementation is MD.HHENCODE. I have tried to use this over the years but have been unsatisfied that it was working as I wanted. (The MD.HHENCODE function is undocumented.) So, to implement a spatial sort that best represents spatial autocorrelation we must implement space curve key generation function on SDO_Geometry. Implementation I have Peano and Morton space-filling curves implemented in C but an implementation in Oracle (as EXPROC) based on these, while technically not difficult, does required changes to the LISTENER which is not popular with many DBAs. I have also converted both these algorithms into Java and have successfully deployed them into the Oracle Java Virtual Machine with PL/SQL wrappers. While not difficult it does require DBA involvement to implement. So, today, after having received an email from a colleague (whom I admire a lot) asking the following question, I decided to try and create a solution based entirely on PL/SQL:
Morton Implementation The original C code for generating a Morton space key is as follows:
Now there are a few difficulties to over-come to get a successful implementation. The first is the use of unsigned integers. To be frank, I am going to ignore this and worry only it if I have to use all 32 bits in generating a key value. The second is the need for a bitwise left << operator. This can be done via the following PL/SQL:
OK, now let’s do the translation to PL/SQL.
A quick test:
Morton Restrictions There is a restriction to how a Morton space curve can be applied: the grid must be regular. This means that while the X and Y dimensions of the grid may be different (ie giving a rectangle not a square) the number of grids either side must be the same (ie a 100×100 grid not a 150×100 grid). Another requirement that affects the generation of a correct space curve is that the (row,column) index values must always be the same. So, in a 100×100 grid the lower left grid should be referenced as (0,0) or (1234,1234) and not (0,1) or (1234, 3456). Apply to Real Data First off let’s generate something that is ideal to our task: random point data. Note that the area, 5000m x 5000m, can be divided in to 100 × 100 × 500m grid cells.
We are not going to create a spatial index as it is not needed. What does this data look like? If we select against the table with no sort we can assume we are getting data as it is physically on disk. Note also, that we want to ensure that our column/row addresses are normalised to the start of the grid.
Note how the data is pretty unsorted. The following image was generated by linking to the MORTON_P table using Manifold GIS and rendering the data by the ID column such that sequential ID column values have roughly the same colour. Note that the colours are displaying randomly which befits the way the data was created and written.
Now, let’s compute the morton key and add it to the base table.
Now let’s create our sorted table using the morton_key value on the base table.
Now select against the table with no sort (assume we are getting data as physically on disk).
Yes, the data is nicely sorted as we want. And visually? Visualising the Morton Key The best way to understand what a space curve is doing is to visualise it via the actual grid and also the actual space curve that passes through the key points in the grid. First, let’s create the grid and visualise it.
Now, let’s look at it. The following image was generated by linking to the MORTONED_GRID table using Manifold GIS and rendering and labelling the data by the MORTON_KEY value.
Notice how the data is colouring shows the relatedness of spatial data next to each grid. But to get a real sense as to how the space curve sort is going to work, let’s create a linestring that passes through the centroids of each grid order by the Morton space curve value.
Here is the space curve superimposed on the labelled Morton grid:
We can also look at the actual point data rendered by the MORTON_KEY and ID columns. Note that the colours are displaying the ordering of the Morton space-curve.
Finally, let’s superimpose the actual point (geometry) data on the 500m x 500m grid with everything rendered by the Morton Key.
I think we can safely assume we have achieved our goal. I hope this is useful to someone. ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]()
![]()
![]() |
Comment [6]
Simon,
Not sure if I misunderstood you. In PostGIS you can do an ORDER BY ageometrycolumn;
What it ends up doing is doing some sort of sort against the bounding box of the geometry.
I haven’t played around to see how that sorting compares to what you have above. It is a common practice to improve performance in PostGIS, by doing a
CLUSTER ON the gist_spatial_index
and that physically sorts the data in the order of the index.
— Regina · 19 September 2009, 06:05 · #
Regina,
Yes, but you can’t ORDER BY sdo_geometry in Oracle!
It is good that you can do it in PostGIS. Most useful in achieving a spatial sort that can help performance of applications like MapServer.
However, the Morton key is a space curve and is more sophisticated object than just coordinates from an MBR. Sorting by X and Y gives you “narrow” stripes of data (still very useful) but it doesn’t enable one to take advantage of the “sideways” relationships (or multidimensional “clusters”) between spatial data in any location. Space-curves give you that better way to represent those spatial correlations and so group the data.
How much better the performance of applications accessing data after a PostGIS or Morton sort is unknown. Perhaps when I get time.
Similarly, one could cluster Oracle data on a Morton key but, again, discussion on that is for another day.
regards
Simon
— Simon · 20 September 2009, 19:59 · #
Simon,
Ah okay. Yes would be interesting to compare the 3.
I think the ORDER BY in PostGIS uses a btree sort (not rtree), where as the CLUSTER ON uses rtree. So I think the CLUSTER ON produces better performance. How that all compares with Morton would be interesting to test.
— Regina · 22 September 2009, 00:18 · #
Regina,
I have revised the article to add in the visualisation of the Mortoned grid and the linestring described by the Morton Key points.
I hope this helps you see how different a space curve can be to a sort based on the coordinates or MBR of a geometry.
regards
Simon
— Simon · 23 September 2009, 10:25 · #
Hi,i’m searching for a java translation of morton code..I’d like to test it for a case study.Could you send it to me?Thanks
— John · 29 October 2010, 01:16 · #
Great article Simon. I have a relatively large spatial table in Oracle (2 million records)with point (address) data. I am in the process of partitioning it to improve performance. Are you aware of any utilities that can prescribe the optimum number of partitions to create the table?
Ideally, such a utility would take into account the max number of desired points in a given partition then extrapolate the required partition ranges.
E.g.
CREATE TABLE new_partn_table (in_date DATE,
geom SDO_GEOMETRY, x_value NUMBER)
PARTITION BY RANGE (X_VALUE)
(PARTITION P_LT_90W VALUES LESS THAN (-90),
PARTITION P_LT_0 VALUES LESS THAN (0),
PARTITION P_LT_90E VALUES LESS THAN (90),
PARTITION P_MAX VALUES LESS THAN (MAXVALUE)
);
— Ross · 23 March 2011, 04:09 · #