簡體   English   中英

Mysql Select 計數與地理空間 ST_Contains 對多行非常慢

[英]Mysql Select count with geospatial ST_Contains is very slow with multiple rows

我有一個 mysql 查詢來獲取一個區域的所有地方計數。 如果我只查詢一個 id 它真的很快,如果我查詢兩個或更多的 id 那么它真的很慢。

Areas.geometry 和 Places.location 是 SPATIAL 索引。

區域表中只有 3 行(都具有復雜的幾何形狀。第 3 行更復雜)和商店中的 3000 行。 如果您想測試,我構建了一個演示 sql 文件以導入: geospatial-exemple.sql

一些例子:

此查詢在 260 毫秒內運行:

    select  a.name, 
            (
            SELECT  count(*)
                FROM  places p
                WHERE  ST_Contains(a.geometry,p.location)
            ) as places_count
        FROM  areas a
        WHERE  a.id in (1) 

在此處輸入圖像描述


此查詢在 320 毫秒內運行:

    select  a.name, 
            (
            SELECT  count(*)
                FROM  places p
                WHERE  ST_Contains(a.geometry,p.location)
            ) as places_count
        FROM  areas a
        WHERE  a.id in (3) 

在此處輸入圖像描述


此查詢在50 秒內運行:

    select  a.name, 
            (
            SELECT  count(*)
                FROM  places p
                WHERE  ST_Contains(a.geometry,p.location)
            ) as places_count
        FROM  areas a
        WHERE  a.id in (1,3) 

在此處輸入圖像描述


我還嘗試使用更復雜的 MULTIPOLYGON 對查詢中的 area.geometry 進行硬編碼

此查詢在 380 毫秒內運行:

    select  a.name, 
            (
            SELECT  count(*)
                FROM  places p
                WHERE  ST_Contains(ST_GeomFromText("MULTIPOLYGON((...))",
                                    4326,
                                    'axis-order=long-lat'),p.location)
            ) as places_count
        FROM  areas a
        WHERE  a.id in (1,3) 

在此處輸入圖像描述


所以很明顯,運行多個查詢比只運行一個並等待一分鍾要快。 如果有人知道這是否是 mysql 錯誤,或者是否有其他方法可以做到這一點? 使用 Join 查詢給出相同的結果。

根據John Powells 的回答,空間索引存在未記錄的限制:

為了使 Contains 和 Intersects 函數正常工作以及要使用的索引,您需要將其中一個幾何圖形設為常量。 這似乎沒有記錄在案,盡管您將看到的所有帶有相交/包含的 MySQL 示例都以這種方式工作。

因此,每個區域運行多個查詢確實會更快。

如果您有權創建函數,則可以通過在 function 中運行子查詢來使用解決方法,其中areas.geometry現在將充當ST_Contains()的常量參數:

CREATE FUNCTION fn_getplacescount(_targetarea GEOMETRY) 
RETURNS INT READS SQL DATA
RETURN (SELECT COUNT(*) FROM places p WHERE ST_Contains(_targetarea, p.location));

現在

SELECT a.name, fn_getplacescount(a.geometry) AS places_count 
FROM areas a WHERE a.id in (1,3);

將類似於單獨運行每個區域,並且應該具有與使用兩個單獨查詢相似的執行時間。

我會嘗試將它表達為一個連接,看看 MySQL 是否運行得更快。 不確定 MySQL 是否優化了空間連接,但在我使用的數據庫中它會更快。

像這樣的東西(我沒有檢查語法):

SELECT areas.name, count(*) as places_count
FROM places p JOIN areas a
ON ST_Contains(a.geometry, p.location)
WHERE a.type = "city"
GROUP BY 1;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM