2013-02-20 21 views
23

Tại sao toán tử "IN" quá chậm khi được sử dụng với truy vấn phụ?Toán tử PostgreSQL IN có hiệu suất phụ truy vấn kém

select * 
from view1 
where id in (1,2,3,4,5,6,7,8,9,10) 
order by somedata; 

thực hiện trong 9ms.

select * 
from view1 
where id in (select ext_id 
      from aggregate_table 
      order by somedata limit 10) 
order by somedata; 

thực hiện trong 25000ms và dường như sử dụng quét tuần tự trên view (view1) thay vì chỉ quét trên khóa chính được trả về bởi subquery như trong thực hiện trong truy vấn đầu tiên.

Các subquery select ext_id from aggregate_table order by somedata limit 10 thực hiện trong 0.1ms

nên sự chậm chạp của truy vấn thứ hai là do quét tuần tự trên view1 đó là một cái nhìn chứa ba công đoàn và khoảng ba tham gia trong mỗi UNION. UNION đầu tiên chứa khoảng 1 triệu hàng, số khác ít hơn nhiều. Tham gia với các bảng có một số hàng 100K. Tuy nhiên, điều đó không liên quan lắm, tôi chỉ muốn hiểu hành vi của toán tử IN.

Điều tôi đang cố gắng thực hiện là lấy kết quả của truy vấn phụ (một bộ khóa chính) và chọn dữ liệu từ chế độ xem phức tạp (view1) chỉ sử dụng chúng.

Tôi cũng không thể sử dụng

select v1.* 
from view1 v1, 
    aggregate_table at 
where v1.id = at.ext_id 
order by at.somedata 
limit 10 

bởi vì tôi không muốn sắp xếp lớn tham gia bằng somedata. Tôi chỉ muốn chọn 10 kết quả từ khung nhìn bằng các khóa chính và sau đó chỉ sắp xếp các kết quả này.

Câu hỏi đặt ra là tại sao toán tử IN thực hiện nhanh khi tôi liệt kê các khóa này một cách rõ ràng và quá chậm khi tôi sử dụng truy vấn con nhanh trả về cùng một nhóm khóa chính xác?

GIẢI THÍCH PHÂN TÍCH theo yêu cầu

đầu tiên truy vấn - select * from view1 where id in (1,2,3,4,5,6,7,8,9,10) order by somedata;

Sort (cost=348.480..348.550 rows=30 width=943) (actual time=14.385..14.399 rows=10 loops=1) 
    Sort Key: "india".three 
    Sort Method: quicksort Memory: 30kB 
    -> Append (cost=47.650..347.440 rows=30 width=334) (actual time=11.528..14.275 rows=10 loops=1) 
     -> Subquery Scan "*SELECT* 1" (cost=47.650..172.110 rows=10 width=496) (actual time=11.526..12.301 rows=10 loops=1) 
       -> Nested Loop (cost=47.650..172.010 rows=10 width=496) (actual time=11.520..12.268 rows=10 loops=1) 
        -> Hash Join (cost=47.650..87.710 rows=10 width=371) (actual time=11.054..11.461 rows=10 loops=1) 
          Hash Cond: (hotel.alpha_five = juliet_xray.alpha_five) 
          -> Bitmap Heap Scan on sierra hotel (cost=42.890..82.800 rows=10 width=345) (actual time=10.835..11.203 rows=10 loops=1) 
            Recheck Cond: (four = ANY ('quebec'::integer[])) 
           -> Bitmap Index Scan on seven (cost=0.000..42.890 rows=10 width=0) (actual time=0.194..0.194 rows=10 loops=1) 
             Index Cond: (four = ANY ('quebec'::integer[])) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.184..0.184 rows=34 loops=1) 
           -> Seq Scan on six juliet_xray (cost=0.000..4.340 rows=34 width=30) (actual time=0.029..0.124 rows=34 loops=1) 
        -> Index Scan using charlie on juliet_two zulu (cost=0.000..8.390 rows=1 width=129) (actual time=0.065..0.067 rows=1 loops=10) 
          Index Cond: (zulu.four = hotel.victor_whiskey) 
     -> Subquery Scan "*SELECT* 2" (cost=4.760..97.420 rows=10 width=366) (actual time=0.168..0.168 rows=0 loops=1) 
       -> Hash Join (cost=4.760..97.320 rows=10 width=366) (actual time=0.165..0.165 rows=0 loops=1) 
         Hash Cond: (alpha_xray.alpha_five = juliet_xray2.alpha_five) 
        -> Nested Loop (cost=0.000..92.390 rows=10 width=340) (actual time=0.162..0.162 rows=0 loops=1) 
          -> Seq Scan on lima_echo alpha_xray (cost=0.000..8.340 rows=10 width=216) (actual time=0.159..0.159 rows=0 loops=1) 
            Filter: (four = ANY ('quebec'::integer[])) 
          -> Index Scan using charlie on juliet_two xray (cost=0.000..8.390 rows=1 width=128) (never executed) 
            Index Cond: (zulu2.four = alpha_xray.victor_whiskey) 
        -> Hash (cost=4.340..4.340 rows=34 width=30) (never executed) 
          -> Seq Scan on six uniform (cost=0.000..4.340 rows=34 width=30) (never executed) 
     -> Subquery Scan "*SELECT* 3" (cost=43.350..77.910 rows=10 width=141) (actual time=1.775..1.775 rows=0 loops=1) 
       -> Hash Join (cost=43.350..77.810 rows=10 width=141) (actual time=1.771..1.771 rows=0 loops=1) 
         Hash Cond: (golf.alpha_five = juliet_xray3.alpha_five) 
        -> Bitmap Heap Scan on lima_golf golf (cost=38.590..72.910 rows=10 width=115) (actual time=0.110..0.110 rows=0 loops=1) 
          Recheck Cond: (four = ANY ('quebec'::integer[])) 
          -> Bitmap Index Scan on victor_hotel (cost=0.000..38.590 rows=10 width=0) (actual time=0.105..0.105 rows=0 loops=1) 
            Index Cond: (four = ANY ('quebec'::integer[])) 
        -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.118..0.118 rows=34 loops=1) 
          -> Seq Scan on six victor_kilo (cost=0.000..4.340 rows=34 width=30) (actual time=0.007..0.063 rows=34 loops=1) 
Total runtime: 14.728 ms 

thứ hai truy vấn - select * from view1 where id in (select ext_id from aggregate_table order by somedata limit 10) order by somedata;

Sort (cost=254515.780..254654.090 rows=55325 width=943) (actual time=24687.475..24687.488 rows=10 loops=1) 
    Sort Key: "five".xray_alpha 
    Sort Method: quicksort Memory: 30kB 
    -> Hash Semi Join (cost=54300.820..250157.370 rows=55325 width=943) (actual time=11921.783..24687.308 rows=10 loops=1) 
      Hash Cond: ("five".lima = "delta_echo".lima) 
     -> Append (cost=54298.270..235569.720 rows=1106504 width=494) (actual time=3412.453..23091.938 rows=1106503 loops=1) 
       -> Subquery Scan "*SELECT* 1" (cost=54298.270..234227.250 rows=1100622 width=496) (actual time=3412.450..20234.122 rows=1100622 loops=1) 
        -> Hash Join (cost=54298.270..223221.030 rows=1100622 width=496) (actual time=3412.445..17078.021 rows=1100622 loops=1) 
          Hash Cond: (three_victor.xray_hotel = delta_yankee.xray_hotel) 
          -> Hash Join (cost=54293.500..180567.160 rows=1100622 width=470) (actual time=3412.251..12108.676 rows=1100622 loops=1) 
            Hash Cond: (three_victor.tango_three = quebec_seven.lima) 
           -> Seq Scan on india three_victor (cost=0.000..104261.220 rows=1100622 width=345) (actual time=0.015..3437.722 rows=1100622 loops=1) 
           -> Hash (cost=44613.780..44613.780 rows=774378 width=129) (actual time=3412.031..3412.031 rows=774603 loops=1) 
             -> Seq Scan on oscar quebec_seven (cost=0.000..44613.780 rows=774378 width=129) (actual time=4.142..1964.036 rows=774603 loops=1) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.149..0.149 rows=34 loops=1) 
           -> Seq Scan on alpha_kilo delta_yankee (cost=0.000..4.340 rows=34 width=30) (actual time=0.017..0.095 rows=34 loops=1) 
       -> Subquery Scan "*SELECT* 2" (cost=4.760..884.690 rows=104 width=366) (actual time=7.846..10.161 rows=104 loops=1) 
        -> Hash Join (cost=4.760..883.650 rows=104 width=366) (actual time=7.837..9.804 rows=104 loops=1) 
          Hash Cond: (foxtrot.xray_hotel = delta_yankee2.xray_hotel) 
          -> Nested Loop (cost=0.000..877.200 rows=104 width=340) (actual time=7.573..9.156 rows=104 loops=1) 
           -> Seq Scan on four_india foxtrot (cost=0.000..7.040 rows=104 width=216) (actual time=0.081..0.311 rows=104 loops=1) 
           -> Index Scan using three_delta on oscar alpha_victor (cost=0.000..8.350 rows=1 width=128) (actual time=0.077..0.078 rows=1 loops=104) 
             Index Cond: (quebec_seven2.lima = foxtrot.tango_three) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.216..0.216 rows=34 loops=1) 
           -> Seq Scan on alpha_kilo quebec_foxtrot (cost=0.000..4.340 rows=34 width=30) (actual time=0.035..0.153 rows=34 loops=1) 
       -> Subquery Scan "*SELECT* 3" (cost=4.760..457.770 rows=5778 width=141) (actual time=0.264..58.353 rows=5777 loops=1) 
        -> Hash Join (cost=4.760..399.990 rows=5778 width=141) (actual time=0.253..39.062 rows=5777 loops=1) 
          Hash Cond: (four_uniform.xray_hotel = delta_yankee3.xray_hotel) 
          -> Seq Scan on whiskey four_uniform (cost=0.000..315.780 rows=5778 width=115) (actual time=0.112..15.759 rows=5778 loops=1) 
          -> Hash (cost=4.340..4.340 rows=34 width=30) (actual time=0.117..0.117 rows=34 loops=1) 
           -> Seq Scan on alpha_kilo golf (cost=0.000..4.340 rows=34 width=30) (actual time=0.005..0.059 rows=34 loops=1) 
     -> Hash (cost=2.430..2.430 rows=10 width=4) (actual time=0.303..0.303 rows=10 loops=1) 
       -> Subquery Scan "ANY_subquery" (cost=0.000..2.430 rows=10 width=4) (actual time=0.092..0.284 rows=10 loops=1) 
        -> Limit (cost=0.000..2.330 rows=10 width=68) (actual time=0.089..0.252 rows=10 loops=1) 
          -> Index Scan using tango_seven on zulu romeo (cost=0.000..257535.070 rows=1106504 width=68) (actual time=0.087..0.227 rows=10 loops=1) 
Total runtime: 24687.975 ms 
+1

Bạn có thể cho chúng tôi thấy CHỌN ANALYZE SELECT ...? Có lẽ sử dụng [depesz] (http://explain.depesz.com/) – MatheusOl

+0

Tôi sẽ thử đặt kết quả truy vấn phụ trong bảng tạm thời, và làm IN (chọn id từ cám dỗ). Sự khác biệt là mệnh đề 'giới hạn' có thể khiến trình tối ưu hóa thực thi chọn lựa cho mỗi hàng trong bảng 1. PS này dường như có hiệu quả giống như @Clodoaldo được đề xuất – rootkit

+0

đã cố gắng 'tạo bảng tạm thời aggregate_table_tmp như chọn ext_id từ thứ tự aggregate_table bởi giới hạn somedata 10' và sau đó sử dụng nó trong truy vấn con' select * từ table1 trong đó id in (select ext_id from aggregate_table_tmp) order bởi somedata' - không may mắn. Cùng 25000ms. – Snifff

Trả lời

29

Có vẻ rằng tôi cuối cùng đã tìm thấy một giải pháp:

select * 
    from view1 
    where view1.id = ANY(
         (select array(select ext_id 
            from aggregate_table 
            order by somedata limit 10) 
         )::integer[] 
        ) 
    order by view1.somedata; 

Sau khi xây dựng @ ý tưởng Dukeling của:

tôi nghi ngờ nơi id trong (1, 2,3,4,5,6,7,8,9,10) có thể được tối ưu hóa và nơi id trong (chọn ...) không thể, lý do là (1,2,3,4,5,6,7,8,9,10) là một biểu thức không đổi, trong khi lựa chọn là thì không.

và định vị những trong kế hoạch truy vấn nhanh hơn

Recheck Cond: (id = ANY ('{1,2,3,4,5,6,7,8,9,10}'::integer[])) 
Index Cond: (id = ANY ('{1,2,3,4,5,6,7,8,9,10}'::integer[])) 

này hoạt động nhanh hơn so với truy vấn đầu tiên trong câu hỏi, khoảng 1.2ms, và bây giờ nó sử dụng

Recheck Cond: (id = ANY ($1)) 
Index Cond: (id = ANY ($1)) 

và bitmap quét trong kế hoạch.

+11

Sử dụng' ARRAY' là một mẹo hay để chỉ dẫn PG sử dụng chỉ mục trong truy vấn phụ. BTW, mệnh đề 'ANY' ở trên có thể được đơn giản hóa thành 'ANY' (array ()) ' –

+0

Tôi không có một dữ liệu lớn (chưa) để thử nghiệm nhưng tại sao' select array (select ...) 'thay vì được gợi ý bởi mảng @BlueSmith' (chọn .. Ví dụ, nếu tôi có giá trị chuỗi, tôi có cần truyền bất kỳ loại nào để có hiệu năng nhanh hơn không? – akostadinov

3

tôi nghi ngờ where id in (1,2,3,4,5,6,7,8,9,10) có thể được tối ưu hóa và where id in (select ...) không thể, lý do là (1,2,3,4,5,6,7,8,9,10) là một hằng số e xpression, trong khi select thì không.

Làm thế nào về:

WITH myCTE AS 
(
    SELECT ext_id 
    FROM aggregate_table 
    ORDER BY somedata 
    LIMIT 10 
) 
SELECT * 
FROM myCTE 
LEFT JOIN table1 
    ON myCTE.ext_id = table1.id 
ORDER BY somedata 
+0

giống như biến thể của @ Clodoaldo, 24000 ms – Snifff

+0

@Snifff Thay đổi thành' LEFT JOIN', có thể tạo sự khác biệt. Tóm lại có vẻ là PostgreSQL đang làm một công việc khủng khiếp khi tối ưu hóa, tôi muốn thấy hiệu năng của MySQL hoặc SQL Server trên cùng một dữ liệu. – Dukeling

+2

'LEFT JOIN' tạo sự khác biệt - thời gian lên đến 65000ms: ( – Snifff

Các vấn đề liên quan