Чому st_intersects швидше, ніж &&


10

Це таблиця балів. ~ 1М записів

SELECT COUNT(*) as value FROM alasarr_social_mv s; 
Output: 976270

Схоже, st_intersects змушує використовувати просторові індекси, але && ні.

Використання зразка ST_Intersects(282 мс)

SELECT COUNT(*) as value
FROM alasarr_social_mv 
WHERE ST_Intersects(
  the_geom_webmercator, 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)
)


Aggregate  (cost=34370.18..34370.19 rows=1 width=0) (actual time=282.715..282.715 rows=1 loops=1)
  ->  Bitmap Heap Scan on alasarr_social_mv s  (cost=5572.17..34339.84 rows=60683 width=0) (actual time=21.574..240.195 rows=178010 loops=1)
        Recheck Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Filter: _st_intersects(the_geom_webmercator, '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Heap Blocks: exact=4848
        ->  Bitmap Index Scan on alasarr_social_mv_gix  (cost=0.00..5569.13 rows=182050 width=0) (actual time=20.836..20.836 rows=178010 loops=1)
              Index Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
Planning time: 0.192 ms
Execution time: 282.758 ms

Використання зразка &&(414 мс)

SELECT COUNT(*) as value
FROM alasarr_social_mv  
WHERE the_geom_webmercator && 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)

Aggregate  (cost=22535.97..22535.97 rows=1 width=0) (actual time=414.314..414.314 rows=1 loops=1)
  ->  Seq Scan on alasarr_social_mv  (cost=0.00..22444.94 rows=182050 width=0) (actual time=0.017..378.427 rows=178010 loops=1)
        Filter: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Rows Removed by Filter: 798260
Planning time: 0.134 ms
Execution time: 414.343 ms

Версія PostGIS

POSTGIS="2.2.2" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.0, released 2014/04/16" LIBXML="2.7.8" LIBJSON="UNKNOWN" (core procs from "2.2.2" need upgrade) RASTER (raster procs from "2.2.2" need upgrade)  alasarr 2 mins ago

2
Не вставляйте скріншоти тексту у запитання. Чи можете ви скопіювати та вставити їх як код? Я не можу їх прочитати, щоб допомогти тобі.
Еван Керролл

Зроблено. Я думаю, зараз трохи краще
жаль,

Я намагався підкріпити ваші нові плани запитів. Не соромтеся оновити плани, але намагайтеся дотримуватися стилю.
Еван Керролл

4
Погляньте на це питання . Оператор && насправді виконує запит на обмежувальний ящик, тоді як ST_Intersects використовує запит на обмежувальну скриньку, щоб визначити, які геометрії потрібно перевірити для фактичного порівняння, тож ви очікуєте, що && буде швидше. Однак, ймовірно, що використання ST_MakeEnvelope праворуч від && змушує планувальник запитів з певних причин обрати повне сканування таблиці (як видно з пояснення). Спробуйте створити геометрію спочатку в CTE і подивіться, чи можете ви «обдурити» оптимізатор.
Джон Пауелл

Ти правий! він працює всередині CTE
жаль,

Відповіді:


16

Такого роду пошук знаходить досить часто, і він трохи незрозумілий, тому варто переглянути його. Якщо ви визначите геометрію у функції, яка її використовує, наприклад, ST_Intersects або && (яку ST_Intersects використовує під кришкою), тоді планувальник запитів вибирає повне сканування таблиці, оскільки "воно" не знає про результат створення геометрії функція, тобто ST_MakeEnvelope в цьому випадку .. Якщо ви визначаєте геометрію, яку потрібно перевірити на перетин в CTE, оптимізатор має справу з відомою кількістю і використовуватиме просторовий індекс, якщо такий є.

Отже, переписавши запит як:

WITH test_geom (geom) AS 
   (SELECT ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857))
  SELECT COUNT(*) as value
    FROM alasarr_social_mv mv, test_geom tg 
   WHERE ST_Intersects(mv.the_geom_webmercator, tg.geom)

тепер використовуватиме просторовий індекс. Так само && тепер використовуватиме індекс для перевірки обмежувального поля, і (поки я не можу перевірити ваші дані) має бути швидшим, ніж ST_Intersects.

Цікаво, що у вашому запиті ST_Intersects використовує індекс растрового сканування (не суть), а && не використовує індекс. Таким чином, обидва запити будуть швидшими за допомогою CTE, але && зараз повинні бути швидшими, ніж ST_Intersects.

Існує більше пояснень того, що відбувається в цьому питанні, та його відповідей / коментарів .

EDIT : Щоб зробити це явним, якщо ви подивитесь на визначення ST_Intersects в postgis.sql (який викликається CREATE EXTENSION postgisі знаходиться в каталозі contrib вашої установки Postgres), ви побачите:

---- Inlines index magic
CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
    RETURNS boolean
    AS 'SELECT $1 OPERATOR(&&) $2 AND _ST_Intersects($1,$2)'
    LANGUAGE 'sql' IMMUTABLE ;

включаючи коментар: вбудовує індекс магію.


1
Я не думаю, що ST_Intersects використовує && під кришкою.
Еван Керролл

4
@EvanCarroll, перевіри мою редагування. Погляньте на postgis.sql, де визначені функції, і це повинно бути чіткіше.
Джон Пауелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.