0

次のSQLクエリを最適化するのに問題があります(postgresql 9.1を使用):

WITH regions AS (
    SELECT r1.region_id
      FROM region r1, 
           (SELECT * 
              FROM region 
             WHERE region_id = 1) r2
     WHERE (r1.region_country = r2.region_country
             OR r2.region_country = 0) 
       AND (r1.region_province = r2.region_province 
             OR r2.region_province = 0) 
       AND (r1.region_area = r2.region_area 
             OR r2.region_area = 0))

SELECT id 
  FROM users 
 WHERE user_region in (SELECT region_id 
                         FROM regions);

Explainは次の出力を生成します

Nested Loop  (cost=85.02..42405.93 rows=13217 width=4) (actual time=0.447..970.132 rows=527444 loops=1)                                                                                                                          
  Buffers: shared hit=464136                                                                                                                                                                                                     
  CTE regions                                                                                                                                                                                                                    
    ->  Nested Loop  (cost=0.00..32.11 rows=5 width=4) (actual time=0.029..0.237 rows=135 loops=1)                                                                                                                               
          Join Filter: (((r1.region_country = region.region_country) OR (region.region_country = 0)) AND ((r1.region_province = region.region_province) OR (region.region_province = 0)) AND ((r1.region_area = region.region_area) OR (region.region_area = 0))) 
          Buffers: shared hit=7                                                                                                                                                                                                  
          ->  Index Scan using region_pkey on region  (cost=0.00..8.27 rows=1 width=6) (actual time=0.015..0.016 rows=1 loops=1)                                                                                                 
                Index Cond: (re_nr = 1)                                                                                                                                                                                          
                Buffers: shared hit=3                                                                                                                                                                                            
          ->  Seq Scan on region r1  (cost=0.00..9.67 rows=567 width=10) (actual time=0.007..0.072 rows=567 loops=1)                                                                                                             
                Buffers: shared hit=4                                                                                                                                                                                            
  ->  HashAggregate  (cost=0.11..0.16 rows=5 width=4) (actual time=0.326..0.449 rows=135 loops=1)                                                                                                                                
        Buffers: shared hit=7                                                                                                                                                                                                    
        ->  CTE Scan on regions  (cost=0.00..0.10 rows=5 width=4) (actual time=0.032..0.278 rows=135 loops=1)                                                                                                                    
              Buffers: shared hit=7                                                                                                                                                                                              
  ->  Bitmap Heap Scan on users  (cost=52.79..8441.69 rows=2643 width=8) (actual time=1.442..6.459 rows=3907 loops=135)                                                                                                   
        Recheck Cond: (user_region = regions.region_id)                                                                                                                                                                            
        Buffers: shared hit=464129                                                                                                                                                                                               
        ->  Bitmap Index Scan on user_region  (cost=0.00..52.13 rows=2643 width=0) (actual time=0.675..0.675 rows=3909 loops=135)                                                                                              
              Index Cond: (user_region = regions.region_id)                                                                                                                                                                        
              Buffers: shared hit=1847                                                                                                                                                                                           
Total runtime: 1003.867 ms                                                                                                                                                                                                       

リージョンクエリの出力を単純に追加すると、すべてが期待どおりに高速になります。

SELECT id
FROM users
WHERE user_region in (1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110)

Explainは次の出力を生成します。

Bitmap Heap Scan on users  (cost=5643.57..135774.21 rows=322812 width=4) (actual time=138.339..365.676 rows=527444 loops=1)                                                                                                                                                                                                                                                                                                                                                                         
  Recheck Cond: (user_region = ANY ('{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110}'::integer[]))     
  Buffers: shared hit=72973 read=1302                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
  ->  Bitmap Index Scan on user_region  (cost=0.00..5562.86 rows=322812 width=0) (actual time=114.446..114.446 rows=527752 loops=1)                                                                                                                                                                                                                                                                                                                                                                      
        Index Cond: (user_region = ANY ('{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110}'::integer[])) 
        Buffers: shared hit=546 read=1301                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
Total runtime: 397.975 ms                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

リージョンクエリ自体の計算も非常に高速です。

Nested Loop  (cost=0.00..32.11 rows=5 width=4) (actual time=0.059..12.323 rows=135 loops=1)                                                                                                                              
  Join Filter: (((r1.region_country = region.region_country) OR (region.region_country = 0)) AND ((r1.region_province = region.region_province) OR (region.region_province = 0)) AND ((r1.region_area = region.region_area) OR (region.region_area = 0))) 
  Buffers: shared hit=1 read=6                                                                                                                                                                                           
  ->  Index Scan using region_pkey on region  (cost=0.00..8.27 rows=1 width=6) (actual time=0.044..0.046 rows=1 loops=1)                                                                                                 
        Index Cond: (re_nr = 1)                                                                                                                                                                                          
        Buffers: shared read=3                                                                                                                                                                                           
  ->  Seq Scan on region r1  (cost=0.00..9.67 rows=567 width=10) (actual time=0.005..12.122 rows=567 loops=1)                                                                                                            
        Buffers: shared hit=1 read=3                                                                                                                                                                                     
Total runtime: 12.379 ms                                                                                                                                                                                                

に列を追加すると、2つの異なる方法の時間差がさらに大きくなりますselect from users

1つの高速クエリですべてを計算する方法はありますか?

ヘルプやソリューションへのポインタは大歓迎です。

[編集]コメントのリクエストに従って地域テーブルのサンプルを追加するユーザーは地域(user_region)を選択できます。これは、国、州、または都市/都市の一部です。リージョンクエリは、その国、州、または都市にあるすべてのregion_idを検索しようとします。ユーザーがオーストリア(region_id = 1)を選択した場合、オーストリアの他のすべてのregion_idよりも返される必要があります。ユーザーが「ニーダーエスターライヒ州」(region_id = 26)を選択した場合、ニーダーエスターライヒ州のすべての地域が返されます(サンプルデータ27、28、29、30)。

select * from region limit 30;
 region_country | region_province | region_area |     region_name     | region_id 
----------------+-----------------+-------------+---------------------+-----------
              1 |               0 |           0 | Austria             |         1
              1 |               1 |           0 | Vienna              |         2
              1 |               1 |           1 | Vienna 1            |         3
              1 |               1 |           2 | Vienna 2            |         4
              1 |               1 |           3 | Vienna 3            |         5
              1 |               1 |           4 | Vienna 4            |         6
              1 |               1 |           5 | Vienna 5            |         7
              1 |               1 |           6 | Vienna 6            |         8
              1 |               1 |           7 | Vienna 7            |         9
              1 |               1 |           8 | Vienna 8            |        10
              1 |               1 |           9 | Vienna 9            |        11
              1 |               1 |          10 | Vienna 10           |        12
              1 |               1 |          11 | Vienna 11           |        13
              1 |               1 |          12 | Vienna 12           |        14
              1 |               1 |          13 | Vienna 13           |        15
              1 |               1 |          14 | Vienna 14           |        16
              1 |               1 |          15 | Vienna 15           |        17
              1 |               1 |          16 | Vienna 16           |        18
              1 |               1 |          17 | Vienna 17           |        19
              1 |               1 |          18 | Vienna 18           |        20
              1 |               1 |          19 | Vienna 19           |        21
              1 |               1 |          20 | Vienna 20           |        22
              1 |               1 |          21 | Vienna 21           |        23
              1 |               1 |          22 | Vienna 22           |        24
              1 |               1 |          23 | Vienna 23           |        25
              1 |               2 |           0 | Lower Austria       |        26
              1 |               2 |           1 | St.Pölten           |        27
              1 |               2 |           2 | Amstetten           |        28
              1 |               2 |           3 | Baden               |        29
              1 |               2 |           4 | Bruck an der Leitha |        30
4

2 に答える 2

1

Aは通常、句joinよりも効率的です。in

.
.
.
SELECT id FROM users 
  INNER JOIN regions ON user_region = region_id;

各ユーザーが 1 つの地域のみに一致すると仮定すると (これはクエリから正しいようです)、同等の結果が得られます。

于 2012-12-14T10:53:12.840 に答える
0

テーブルを分析しようとしましたか?

あなたが投稿した説明から、Postgresが実際に返された行数の最大 39 分の 1 を期待していたことがわかります。

Postgres の予想が実際の結果セットと大きく異なる場合、最適ではないプランが選択される可能性があります。その結果、劣悪なクエリ プランが生成され、クエリの完了に時間がかかります。

于 2014-04-07T17:40:03.600 に答える