2017-12-06 12 views
2

저는 postgres v9.6.5를 사용하고 있습니다. 복잡한 쿼리를 사용하지 않고 왜 느려지는지 궁금해하고 있습니다. (실제로 느리지 만 실제로는 수천 행과 같은 많은 데이터가 없습니다.) 여기 포스트그레스 쿼리를 설명하십시오. 왜 훨씬 더 길고 WHERE 및 LIMIT를 사용하는 쿼리입니까

쿼리입니다 :

SELECT o0.* 
FROM "orders" AS o0 
JOIN "balances" AS b1 ON b1."id" = o0."balance_id" 
JOIN "users" AS u3 ON u3."id" = b1."user_id" 
WHERE (u3."partner_id" = 3) 
ORDER BY o0."id" DESC LIMIT 10; 

그리고 그 쿼리 계획이다 :

Limit (cost=0.43..12.84 rows=10 width=148) (actual time=0.062..53.866 rows=4 loops=1) 
    -> Nested Loop (cost=0.43..4750.03 rows=3826 width=148) (actual time=0.061..53.864 rows=4 loops=1) 
     Join Filter: (b1.user_id = u3.id) 
     Rows Removed by Join Filter: 67404 
     -> Nested Loop (cost=0.43..3945.32 rows=17856 width=152) (actual time=0.025..38.457 rows=16852 loops=1) 
       -> Index Scan Backward using orders_pkey on orders o0 (cost=0.29..897.80 rows=17856 width=148) (actual time=0.016..11.558 rows=16852 loops=1) 
       -> Index Scan using balances_pkey on balances b1 (cost=0.14..0.16 rows=1 width=8) (actual time=0.001..0.001 rows=1 loops=16852) 
        Index Cond: (id = o0.balance_id) 
     -> Materialize (cost=0.00..1.19 rows=3 width=4) (actual time=0.000..0.000 rows=4 loops=16852) 
       -> Seq Scan on users u3 (cost=0.00..1.18 rows=3 width=4) (actual time=0.023..0.030 rows=4 loops=1) 
        Filter: (partner_id = 3) 
        Rows Removed by Filter: 12 
Planning time: 0.780 ms 
Execution time: 54.053 ms 

실제로 LIMIT없이 노력하고 내가 상당히 다른 계획을 가지고 : 또한

Sort (cost=874.23..883.80 rows=3826 width=148) (actual time=11.361..11.362 rows=4 loops=1) 
    Sort Key: o0.id DESC 
    Sort Method: quicksort Memory: 26kB 
    -> Hash Join (cost=3.77..646.55 rows=3826 width=148) (actual time=11.300..11.346 rows=4 loops=1) 
     Hash Cond: (o0.balance_id = b1.id) 
     -> Seq Scan on orders o0 (cost=0.00..537.56 rows=17856 width=148) (actual time=0.012..8.464 rows=16852 loops=1) 
     -> Hash (cost=3.55..3.55 rows=18 width=4) (actual time=0.125..0.125 rows=24 loops=1) 
       Buckets: 1024 Batches: 1 Memory Usage: 9kB 
       -> Hash Join (cost=1.21..3.55 rows=18 width=4) (actual time=0.046..0.089 rows=24 loops=1) 
        Hash Cond: (b1.user_id = u3.id) 
        -> Seq Scan on balances b1 (cost=0.00..1.84 rows=84 width=8) (actual time=0.011..0.029 rows=96 loops=1) 
        -> Hash (cost=1.18..1.18 rows=3 width=4) (actual time=0.028..0.028 rows=4 loops=1) 
          Buckets: 1024 Batches: 1 Memory Usage: 9kB 
          -> Seq Scan on users u3 (cost=0.00..1.18 rows=3 width=4) (actual time=0.014..0.021 rows=4 loops=1) 
           Filter: (partner_id = 3) 
           Rows Removed by Filter: 12 
Planning time: 0.569 ms 
Execution time: 11.420 ms 

그리고없이를 WHERE (단 LIMIT) :

Limit (cost=0.43..4.74 rows=10 width=148) (actual time=0.023..0.066 rows=10 loops=1) 
    -> Nested Loop (cost=0.43..7696.26 rows=17856 width=148) (actual time=0.022..0.065 rows=10 loops=1) 
     Join Filter: (b1.user_id = u3.id) 
     Rows Removed by Join Filter: 139 
     -> Nested Loop (cost=0.43..3945.32 rows=17856 width=152) (actual time=0.009..0.029 rows=10 loops=1) 
       -> Index Scan Backward using orders_pkey on orders o0 (cost=0.29..897.80 rows=17856 width=148) (actual time=0.007..0.015 rows=10 loops=1) 
       -> Index Scan using balances_pkey on balances b1 (cost=0.14..0.16 rows=1 width=8) (actual time=0.001..0.001 rows=1 loops=10) 
        Index Cond: (id = o0.balance_id) 
     -> Materialize (cost=0.00..1.21 rows=14 width=4) (actual time=0.001..0.001 rows=15 loops=10) 
       -> Seq Scan on users u3 (cost=0.00..1.14 rows=14 width=4) (actual time=0.005..0.007 rows=16 loops=1) 
Planning time: 0.286 ms 
Execution time: 0.097 ms 

WHERE이 없으면 훨씬 빠릅니다. 누군가가 나를 더 잘 이해할 수있는 계획에 대한 설명을 어디서 찾을 수 있습니까? 또한 이러한 쿼리를 더 빨리 수행하기 위해 무엇을 할 수 있습니까? 아니면 100 배나 더 많은 데이터를 가지고도 충분히 빠를 것입니다 .- 내게 50ms가 적당합니다. tb30)

답변

2

PostgreSQL은 WHERE 조건을 만족하는 일치하는 users 항목을 찾을 때까지 올바른 순서로 orders을 검색하면 가장 빠릅니다.

그러나 일치가 발견되기 전에 데이터 배포가 거의 17000 orders 개를 스캔해야하는 것처럼 보입니다.

PostgreSQL은 값이 테이블간에 어떻게 상관되는지 알지 못하기 때문에 변경할 수있는 방법이 많지 않습니다.

이 같은 LIMIT 절없이 쿼리를 계획하는 PostgreSQL을 강제 할 수 있습니다 :

SELECT * 
FROM (<your query without ORDER BY and LIMIT> OFFSET 0) q 
ORDER BY id DESC LIMIT 10; 

를이 더 잘 수행해야 최고-N-종류로.

+0

감사합니다. –