STIntersects'in performansını artırma


11

Tabloda T_PIN300.000 pim ve T_POLYGON36.000 çokgen vardır. T_PINşu dizine sahip:

CREATE SPATIAL INDEX [T_PIN_COORD] ON [dbo].[T_PIN]
(
[Coord]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY];

T_POLYGON vardır:

CREATE SPATIAL INDEX [T_POLYGON_COORD] ON [dbo].[T_POLYGON]
(
[COORD]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY];

Bir sorgu kesişim bulmak için T_PINve T_POLYGONyürütmek fazla 45 dakika sürer:

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;

Sonuç 4.438.318 satırdır.

Bu sorguyu nasıl hızlandırabilirim?


`T_POLYGON.Coord.STIntersects (T_PIN.COORD) = 1 'kullanmayı denediniz mi?
travis

Sorgu planınızı görmek isterim. Postgres üzerinde çalışıyorum, ancak benzer sorgular, ancak önemli ölçüde daha büyük veri kümeleri çalıştırmak zorunda. En kötü olanları yaklaşık 2 güne düşüren bir teknikle geldim (maalesef komut dosyası oluşturmayı içeriyor), ancak önce sorgu planınızı görmek isterim.
John Powell

İki tablomdaki çokgenleri birlikte çarptığımda, kombinasyonunuzda olduğundan daha fazla potansiyel kavşak sayısı açısından 7000 kat daha fazla bir sayı var, bu yüzden iki günüm oldukça iyi görünüyor. Bununla birlikte, bir sorgu planı görmeden ve çokgen başına ortalama nokta sayısı hakkında bir şey bilmeden, somut çözümler bulmak zor olacaktır.
John Powell

Yanıtlar:


7

İlk olarak, sorgu yürütme planına bakarak uzamsal bir dizinin kullanılıp kullanılmadığını kontrol edin ve Kümelenmiş Dizin Araması (Uzamsal) öğesi olup olmadığına bakın.

Kullanıldığı varsayılarak, önce kontrol etmek için basitleştirilmiş çokgenlere sahip bir sınırlayıcı kutuya dayalı ikincil / basitleştirilmiş bir filtre eklemeyi deneyebilirsiniz. Bu basitleştirilmiş çokgenlere karşı eşleşmeler daha sonra nihai sonuçları elde etmek için birincil filtreden geçirilebilir.

1) [dbo]. [T_POLYGON] tablosuna yeni bir coğrafya ve geometri sütunu ekleyin:

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;

2) Sınırlayıcı kutu çokgenleri oluşturun (STEnvelope () yönteminden yararlanmak için geometriye ilk dönüştürmeyi içerir):

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeom = geometry::STGeomFromWKB(
    COORD.STAsBinary(), COORD.STSrid).STEnvelope();

UPDATE [dbo].[T_POLYGON] SET SimplePolysGeog = geography::STGeomFromWKB(
    SimplePolysGeom.STAsBinary(), SimplePolysGeom.STSrid);

3) Basitleştirilmiş coğrafya sütununda uzamsal bir dizin oluşturun

4) Bu basitleştirilmiş coğrafya sütununa karşı kesişimleri alın, ardından eşleşen coğrafya veri türlerine tekrar filtre uygulayın. Kabaca, böyle bir şey:

;WITH cte AS
(
   SELECT pinID, polygonID FROM T_PIN INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.SimplePolysGeog ) = 1
)
SELECT COUNT(*)
FROM T_PIN 
INNER JOIN T_POLYGON
    ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1
    AND T_PIN.pinID IN (SELECT pinID FROM cte)
    AND T_POLYGON.polygonID IN (SELECT polygonID FROM cte)

DÜZENLEME : (1) ve (2) 'yi bu hesaplanmış, kalıcı sütunla değiştirebilirsiniz. öneri için Paul White'a teşekkür ederiz.

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS  ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTED

Evet, az ya da çok bunu yapıyordum. Geniş bir kapsama alanına sahip iki tablo kümesini uzaysal olarak "birleştirirken" bulduğum sorun, optimizatörün genellikle iki tam tablo taraması ve çokgen testlerinde çok fazla noktaya gitmesidir.
John Powell

2

Bu tür sorgular çokgenlerin karmaşıklığı nedeniyle genellikle uzun zaman alır. Karmaşık sahil şeritlerinin (örneğin) sınırlarına yakın olan noktaları test etmek için yaşları aldığını gördüm, bir noktanın içeride veya dışarıda olup olmadığını bulmak için birçok seviyeyi yakınlaştırmak zorunda kaldım.

... böylece .Reduce()çokgenleri deneyebilir , bunun işe yarayıp yaramadığını görmek için.

Bu işlev hakkında daha fazla bilgi için http://msdn.microsoft.com/en-us/library/cc627410.aspx adresine bakın.


1

Microsoft belgelerine göre, uzamsal dizinler, bir cümle ile karşılaştırma yükleminin başlangıcında göründüklerinde aşağıdaki yöntemlerde coğrafya türleriyle kullanılacaktır WHERE:

  • STIntersects
  • STDistance
  • STEquals

Yalnızca geometri türlerinin yöntemleri (kısıtlı liste), uzamsal dizin kullanımını tetikleyecektir JOIN ... ON, bu nedenle kullanılacak kodunuzu değiştirin WHERE geog1.STIntersects(geog2) = 1ve bu da hızı artırmalıdır.

Ayrıca g2server'ın cevabında tavsiye almanızı ve filtreleme için aşağıdakileri eklemenizi ve üzerine uzamsal dizin eklemenizi öneririm

ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS
     ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),
                                                           [COORD].[STSrid])
                 .STEnvelope().STAsBinary(),(4326))) PERSISTED

Daha sonra aşağıdaki gibi bir sorgu olabilir (i hızla bu yazı yazdı ve henüz test değil, bu sadece denemek için bir şey çünkü ben sorgunuzu ve en yüksek gönderilen cevaplar kullanmak kullanmaz spatial op = 1 JOIN ON gördüm uzamsal dizin):

SELECT   
     (SELECT p2.polygon_id
      FROM   T_Polygon p2
      WHERE  p2.coords.STIntersects(t.coords) = 1),
     t.pin_id
FROM     T_PIN t
WHERE    
     (SELECT t.coords.STIntersects(p.coords)
      FROM   T_POLYGON p
      WHERE  t.coords.STIntersects(p.SimplePolysGeog) = 1) = 1

FYI: Eğer SimplePolysGeogüst üste binme (yukarıda bir pimde olduğu gibi iki basitleştirilmiş coğrafyada olduğu gibi), yukarıdaki durum işe yaramaz, bunu sadece bir eyaletteki bölgelerdeki insanlar üzerinde çalıştırdı ve normal polisler sınır paylaştığından, sınırlayıcı kutular üst üste geldi, bu yüzden çoğu kullanımda durumlarda, alt sorgunun birden fazla sonuç döndürdüğü hatası verir.

MS Docs'un Mekansal Dizinlerine Genel Bakış :

Mekansal Endekslerle Desteklenen Coğrafya Yöntemleri

Belirli koşullar altında, uzamsal dizinler aşağıdaki küme odaklı coğrafya yöntemlerini destekler: STIntersects (), STEquals () ve STDistance (). Bir uzamsal dizin tarafından desteklenmek için, bu yöntemler bir sorgunun WHERE yan tümcesinde kullanılmalı ve aşağıdaki genel formun bir yüklemesi içinde gerçekleşmelidir:

geography1.method_name (geography2) comparison_operatorvalid_number

Boş olmayan bir sonuç döndürmek için, coğrafya1 ve coğrafya2 aynı Uzamsal Referans Tanımlayıcısına (SRID) sahip olmalıdır . Aksi takdirde, yöntem NULL döndürür.

Uzamsal dizinler aşağıdaki yüklem formlarını destekler:


Uzamsal Dizinler kullanan sorgular

Uzamsal dizinler yalnızca WHERE yan tümcesinde bir dizinlenmiş uzamsal işleç içeren sorgularda desteklenir. Örneğin, aşağıdaki gibi sözdizimi:

[spatial object].SpatialMethod([reference spatial object]) [ = | < ] [const literal or variable]

Sorgu iyileştirici, uzamsal işlemlerin değişebilirliğini (o @a.STIntersects(@b) = @b.STInterestcs(@a)) anlar . Ancak, karşılaştırmanın başlangıcı uzamsal işleç içermiyorsa WHERE 1 = spatial opuzamsal dizin kullanılmayacaktır (örneğin uzamsal dizin kullanılmayacaktır). Uzamsal dizini kullanmak için karşılaştırmayı yeniden yazın (örneğin WHERE spatial op = 1).

...

SimplePolysGeogsÇakışma durumunda aşağıdaki sorgu çalışır :

;WITH cte AS
(
   SELECT T_PIN.PIN_ID, 
          T_POLYGON.POLYGON_ID, 
          T_POLYGON.COORD 
   FROM T_PIN 
   INNER JOIN T_POLYGON
   ON T_PIN.COORD.STIntersects(T_POLYGON.SimplePolysGeog) = 1
)

SELECT COUNT(*)
FROM T_PIN 
INNER JOIN cte
ON T_PIN_PIN_ID = cte.PIN_ID
where cte.[COORD].STIntersects(T_PIN.COORD) = 1
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.