简体   繁体   English

如何通过子查询(可能通过横向联接)优化sql查询?

[英]How to optimize sql query with subqueries, perhaps by lateral join?

I'm trying to optimize sophisticated sql query, it would be executed on each map bonding box change. 我正在尝试优化复杂的sql查询,它将在每次地图绑定框更改时执行。 I thought that INNER LATERAL JOIN would be fastest but it isn't. 我以为INNER LATERAL JOIN最快,但不是。 Does anybody know how to speed up this query and how to make better use of LATERAL JOIN ? 有人知道如何加快查询速度,以及如何更好地利用LATERAL JOIN吗?

The fastest query I've made: 我进行的最快查询:

SELECT r0."id", r0."name" 
FROM "hiking"."routes" AS r0 
INNER JOIN "hiking"."hierarchy" AS h1 ON r0."id" = h1."parent" 
INNER JOIN (SELECT DISTINCT unnest(s0."rels") AS "rel" 
            FROM "hiking"."segments" AS s0 
            WHERE (ST_Intersects(s0."geom", ST_SetSrid(ST_MakeBox2D(ST_GeomFromText('POINT(1285982.015631 7217169.814674)', -1), ST_GeomFromText('POINT(2371999.313507 6454022.524275)', -1)), 3857)))) AS s2 ON TRUE 
WHERE (s2."rel" = h1."child");

Planning time: ~0.605 ms Execution time: ~37.232 ms 计划时间:〜0.605毫秒执行时间:〜37.232毫秒

Actually the same as above but with LATERAL JOIN , is it correct that it is slower? 实际上与上面相同,但使用LATERAL JOIN ,速度较慢是否正确?

SELECT r0."id", r0."name" 
FROM "hiking"."routes" AS r0 
INNER JOIN "hiking"."hierarchy" AS h1 ON r0."id" = h1."parent" 
INNER JOIN LATERAL (SELECT DISTINCT unnest(s0."rels") AS "rel" 
                    FROM "hiking"."segments" AS s0 
                    WHERE (ST_Intersects(s0."geom", ST_SetSrid(ST_MakeBox2D(ST_GeomFromText('POINT(1285982.015631 7217169.814674)', -1), ST_GeomFromText('POINT(2371999.313507 6454022.524275)', -1)), 3857)))) AS s2 ON TRUE 
WHERE (s2."rel" = h1."child");

Planning time: ~1.353 ms Execution time: ~38.518 ms 计划时间:〜1.353毫秒执行时间:〜38.518毫秒

Slowest query with subquery in subquery (that was my first so I've improved it a bit): 子查询中子查询中最慢的查询(这是我的第一个查询,因此我对其进行了一些改进):

SELECT r0."id", r0."name" 
FROM "hiking"."routes" AS r0 
INNER JOIN (SELECT DISTINCT h0."parent" AS "parent" 
            FROM "hiking"."hierarchy" AS h0 
            INNER JOIN (SELECT DISTINCT unnest(s0."rels") AS "rel" 
                        FROM "hiking"."segments" AS s0 
                        WHERE (ST_Intersects(s0."geom", ST_SetSrid(ST_MakeBox2D(ST_GeomFromText('POINT(1285982.015631 7217169.814674)', -1), ST_GeomFromText('POINT(2371999.313507 6454022.524275)', -1)), 3857)))) AS s1 ON TRUE 
            WHERE (h0."child" = s1."rel")) AS s1 ON TRUE 
WHERE (r0."top" AND (r0."id" = s1."parent"));

Planning time: ~1.017 ms Execution time: ~41.288 ms 计划时间:〜1.017毫秒执行时间:〜41.288毫秒

It is hard to reproduce the logic of your query without any knowledges about your DB but I will try, so be patient: 在没有任何有关数据库的知识的情况下,很难重现查询的逻辑,但是我会尽力的,所以请耐心等待:

SELECT r0."id", r0."name" 
FROM "hiking"."routes" AS r0 
INNER JOIN "hiking"."hierarchy" AS h1 ON r0."id" = h1."parent" 
WHERE 
  EXISTS (
    SELECT 1
    FROM "hiking"."segments" AS s0 
    WHERE (
      ST_Intersects(
        s0."geom",
        ST_SetSrid(ST_MakeBox2D(ST_GeomFromText('POINT(1285982.015631 7217169.814674)', -1), ST_GeomFromText('POINT(2371999.313507 6454022.524275)', -1)),
        3857)))
      AND array[h1."child"] <@ s0."rels");

There are two points: 有两点:

  1. Filtering data by EXISTS or NOT EXISTS sometimes faster then by joining 通过EXISTSNOT EXISTS筛选数据有时会比通过加入来更快
  2. Instead of unnesting array field to compare its elements with some value you could to use the array comparison operator(s). 除了取消嵌套数组字段以将其元素与某个值进行比较之外,您还可以使用数组比较运算符。 Having appropriate GIN index it is much faster (docs here and here ). 有了适当的GIN索引,速度会更快( 此处此处的文档)。

Here is simple example how to use indexes on arrays and how its faster: 这是一个简单的示例,说明如何在数组上使用索引及其速度如何:

create table foo(bar int[]);
insert into foo(bar) select array[1,2,3,x] from generate_series(1,1000000) as x;
create index idx on foo using gin (bar); // Note this
select * from foo where 666 in (select unnest(bar)); // 6936,345 ms on my HW
select * from foo where array[666] <@ bar; // 45,524 ms

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM