GIS

Ray Chilcote, PG, GISP NCDOT IT/GIS Overview  NCDOT data  Changes/growth going to ROME (R&H)  Producing Road Characteristics  Old method  New ...
Author: Sharleen Cole
6 downloads 2 Views 3MB Size
Ray Chilcote, PG, GISP NCDOT IT/GIS

Overview  NCDOT data  Changes/growth going to ROME (R&H)

 Producing Road Characteristics  Old method  New method  Use of views  Dynamic labeling (measures)  Storage, speed

Dynamic

 Bonus round

Speed Automation

NCDOT Data – before migration  86,000 individual routes  70+ linear event tables  Overnight process to merge Routes and Events

NCDOT Data – after migration  146,000 individual routes  Added local, non-system

 ~50 linear event tables  Condensed (example: Addition, Addition Date)

 Implement history  Closer to real time

Data Output Considerations

 Database architecture  Speed

 Maintenance  Change management  Documentation  QC

Edit environment output

Original Challenge Intersect several event tables (~70) into one. Measures are not always coincident.

Duc Tran Author: Duc-Tran date-written: Jul-10-08 select * from s_medtyp order by 1,2; FTSEG FRM_PCT_QTY TO_PCT_QTY MEDTYP ---------- ----------- ---------- ---------1 0 .1 1 1 .1 .2 2 1 .3 1 8 select * from s_medwidth order by 1,2; FTSEG FRM_PCT_QTY TO_PCT_QTY MEDWITH ---------- ----------- ---------- ---------1 0 .2 20 1 .2 .5 30 1 .5 .6 20 1 .6 1 70 select * from s_speed order by 1,2; FTSEG FRM_PCT_QTY TO_PCT_QTY SPEED ---------- ----------- ---------- ---------1 0 .2 25 1 .4 1 70 2 0 1 75

DECLARE list_fld VARCHAR2(32767); schema_nm VARCHAR2(30); list_tbl_fld VARCHAR2(32767); sel_dstnct_tbl VARCHAR2(32767); union_blk VARCHAR2(32767); last_tbl VARCHAR2(30); where_outer_blk VARCHAR2(32767); between_blk VARCHAR2(32767); plsql_blk CLOB; high_g1 number; low_g1 number;

PLSQL writing PLSQL (Oracle) (Oracle)

CURSOR get_all_recs IS select ATRBT_TBL_NM, RC_COL_NM, ATRBT_ID from gis_arid.fpl_atrbt_metadata a, all_tables b where a.ATRBT_TBL_NM = b.TABLE_NAME and a.ATRBT_TBL_OWNR_NM = b.OWNER and a.IS_EVNT_IND_NM = 'YES'; BEGIN schema_nm := 'GIS_ARID'; FOR rec IN get_all_recs LOOP list_fld := list_fld || rec.RC_COL_NM || ', '; list_tbl_fld := list_tbl_fld || ' b' || rec.ATRBT_ID || '.' || rec.RC_COL_NM || ', '; sel_dstnct_tbl := sel_dstnct_tbl || '(SELECT DISTINCT G1_FTSEG_ID, FRM_EVNT_PCT, TO_EVNT_PCT, ' || rec.RC_COL_NM || ' FROM ' || schema_nm || '.' || rec.ATRBT_TBL_NM || ') b' || rec.ATRBT_ID || ','; union_blk := union_blk || 'SELECT DISTINCT G1_FTSEG_ID, TO_EVNT_PCT FROM ' || schema_nm || '.' ||rec.ATRBT_TBL_NM || ' UNION '; union_blk := union_blk || 'SELECT DISTINCT G1_FTSEG_ID, FRM_EVNT_PCT FROM ' || schema_nm || '.' ||rec.ATRBT_TBL_NM || ' UNION '; last_tbl := schema_nm || '.' ||rec.ATRBT_TBL_NM; where_outer_blk := where_outer_blk || 'a.G1_FTSEG_ID = b' || rec.ATRBT_ID || '.G1_FTSEG_ID(+) and '; between_blk := between_blk || 'a.frm + .0000005 between b' || rec.ATRBT_ID || '.FRM_EVNT_PCT(+) and b' || rec.ATRBT_ID || '.TO_EVNT_PCT(+) and '; END LOOP; --Cleanup unwanted TEXT at end of strings list_fld := RTRIM(list_fld, ', '); list_tbl_fld := RTRIM(list_tbl_fld, ', '); between_blk := RTRIM(between_blk, 'and ');

-- BUILD STATEMENT plsql_blk := 'insert into plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk || plsql_blk := plsql_blk ||

rlchilcote.fpl_rd_char (g1_ftseg_id, frm_evnt_pct, to_evnt_pct, ' || list_fld || ')'; 'select distinct a.G1_FTSEG_ID,a.frm fpc,a.two tpc,'; list_tbl_fld || ' FROM '; sel_dstnct_tbl; '(select distinct a.G1_FTSEG_ID,a.frm,b.two from '; '(select distinct G1_FTSEG_ID,TO_EVNT_PCT frm,rownum n1 from ('; union_blk || ' SELECT G1_FTSEG_ID, min(FRM_EVNT_PCT) mini FROM ' || last_tbl || ' GROUP BY G1_FTSEG_ID)) a, '; '(select distinct G1_FTSEG_ID,TO_EVNT_PCT two,rownum n2 from ('; union_blk || ' SELECT G1_FTSEG_ID, min(FRM_EVNT_PCT) mini FROM ' || last_tbl || ' GROUP BY G1_FTSEG_ID)) b '; 'where a.G1_FTSEG_ID=b.G1_FTSEG_ID and a.n1+1=b.n2) a '; 'where ' || where_outer_blk; 'a.G1_FTSEG_ID BETWEEN 150000 AND 200000 AND '; between_blk || '; ';

plsql_blk := plsql_blk || 'COMMIT;';

EXECUTE IMMEDIATE plsql_blk; COMMIT; END;



Aggregation Query

Python

(SQL Server)

Formatted, produces a single, 4500 line long sql statement. 45 pages. Front and back.

Results 1 Single semi-dynamic SQL query Produces 1 table Time required: 40 minutes (priceless)

~ 95 event fields

• • •

… 566k rows (unique Route Event Characteristic sections, original edit sections dissolved if same value)

Challenge: Show locked routes • • • •

ArcMap Query Layer Spatial View in Database Dynamic Where Clause Other • Custom GP (created each time?)

ArcMap Query Layer

Honors ArcSDE Versions!

Does NOT work with RCE

View in Database

Actually, quite nice and simple. Automagically shows up as a feature class in SDE

Make Uber-Dynamic Where Clause You are here

MilePoint_ID in (select distinct RouteID from GdbRomeEdit.Rome.Lrs_Locks) And (FromDate is null or FromDateCURRENT_TIMESTAMP)

Uber simple. Nothing to create in Database. Same query. Directly created into a service.

Show (Label) Measure Length

Show Measure Length

Storage, Speed

• Measure value is multiplied by the Resolution to create the stored integer • Several issues: • Number in not number out • (old feature creep?) • Database size impacted • Speed impacted

Storage, Speed

How issue came into focus Show of hands, who has had issues with gaps and overlaps? Found that Beginning/End Measure in the shape was not the same value as the FromMeasure and ToMeasure in the Roads and Highways Event data.

NHS Before Fix (6 decimal) NHS Before fix (15 decimal)

NHS After fix (15 decimal)

Spatially, verticies contiguous. So decided to fix Resolution, then recalc all FromMeasure/ToMeasure/Measure fields

Before

QA Gray is GOOD!

• Python script written to order Route/Measure (field). • Then find gaps with a tolerance. • When gap found, list the first record.

After

Storage Gains 14.7 million verticies, each with a measure. Solely changing the database M resolution…

FromMeasure and ToMeasure field values now equal Shape measures.

In Summary: Don’t Forget…    

Gather requirements first (good requirements) Attribute indexing View or query/create subset? (balance ROI) Issue Analysis (execution plan, database tracing, Perfmon)  Too often, system is fast enough. Slowing system. Generally, the problem is not server

horsepower.  Query order matters. A lot.  Are NULLs causing issues? Reconciles, statistics, etc.

 Good database design  Utilize database strengths  Separate editing and publication requirements  Good to have editing look like publication, but not at the sacrifice of editing woes.

Bonus Round  Speed  Indexes  

Utilize! Nulls are bad  Database constraints, if possible  If Sql Server, look up Filtered Index

 Compress  If possible in your workflow, compress. Often.  Reconcile often  Gather statistics

 Metadata  Say what is this doing here?

Versioning Artwork

Questions? Contact info: [email protected]

Balance ROI Going too far

Example:  Challenge: Place Road Characteristics (events) on network (route)  Problem: Road Characteristics do not begin/end on route (network) nodes  Attempt to find measure on route where there is no node (interpolate) in SQL  Worked SQL query to return route, measure, X, Y, elevation for nodes  Interpolated between previous/next record with LEAD/LAG  13.7 million nodes. Need to store. t = time requirement to calc/update

 Why do all this? Make Features Route tool does this activity in < 5

minutes for the entire state. Natively exports in a few more minutes.

Too far SELECT b.OBJECTID ,a.milepoint_id RouteID ,a.shape.STPointN(b.objectid).M Measure ,a.shape.STPointN(b.objectid).STX X ,a.shape.STPointN(b.objectid).STY Y ,a.shape.STPointN(b.objectid).Z Z ,geometry::STGeomFromText('POINT (' + CONVERT(varchar(20), CONVERT(varchar(20), CONVERT(varchar(20), CONVERT(varchar(20), , 2264 ) AS g FROM gdbgisustage.rome.lrsn_milepoint AS a, gdbgisustage.rome.lrsn_milepoint AS b WHERE b.objectid BETWEEN 1 AND a.shape.STNumPoints() AND a.milepoint_id = '20000052029'

a.shape.STPointN(b.objectid).STX) a.shape.STPointN(b.objectid).STY) a.shape.STPointN(b.objectid).Z) + a.shape.STPointN(b.objectid).M) +

+ ' ' + + ' ' + ' ' + ')'

Geodatabase Architecture