4

次のクエリは、約 400 万行で実行されています。最初の 2 つの CTE ステートメントは、約 1 時間で実行されます。しかし、最後のものは 15 年以上続く予定です。

WITH parsed AS (
   SELECT name, array(...) description FROM import
), counts AS (
   SELECT unnest(description) token, count(*) FROM parsed GROUP BY 1
) 
INSERT INTO table (name, description) 
SELECT name, ARRAY(
    SELECT ROW(token, count)::a 
    FROM (
        SELECT token, (
            SELECT count 
            FROM counts 
            WHERE a.token=counts.token
            ) 
        FROM UNNEST(description) a(token)
        ) _
    )::a[] description 
FROM parsed;

                                                                  QUERY PLAN                                                                   
-----------------------------------------------------------------------------------------------------------------------------------------------
 Insert on table  (cost=55100824.40..162597717038.41 rows=3611956 width=96)
   CTE parsed
     ->  Seq Scan on import  (cost=0.00..51425557.67 rows=3611956 width=787)
           Filter: ((name IS NOT NULL) AND (description IS NOT NULL))
           SubPlan 1
             ->  HashAggregate  (cost=11.59..12.60 rows=101 width=55)
                   ->  Append  (cost=0.00..11.34 rows=101 width=55)
                         ->  Result  (cost=0.00..0.01 rows=1 width=0)
                         ->  Index Scan using import_aliases_mid_idx on import_aliases  (cost=0.00..10.32 rows=100 width=56)
                               Index Cond: (mid = "substring"(import.mid, 5))
           SubPlan 2
             ->  HashAggregate  (cost=0.78..1.30 rows=100 width=0)
                   ->  Result  (cost=0.00..0.53 rows=100 width=0)
   CTE counts
     ->  HashAggregate  (cost=3675165.23..3675266.73 rows=20000 width=32)
           ->  CTE Scan on parsed  (cost=0.00..1869187.23 rows=361195600 width=32)
   ->  CTE Scan on parsed  (cost=0.00..162542616214.01 rows=3611956 width=96)
         SubPlan 6
           ->  Function Scan on unnest a  (cost=0.00..45001.25 rows=100 width=32)
                 SubPlan 5
                   ->  CTE Scan on counts  (cost=0.00..450.00 rows=100 width=8)
                         Filter: (a.token = token)

と の両方に約 400 万行parsedありcountsます。クエリは現在実行中で、最後のステートメントは約 2 分ごとに行を挿入しています。ディスクにはほとんど触れていませんが、CPUを狂ったように食べており、混乱しています。

クエリの何が問題になっていますか?

最後のステートメントは、 in の各要素を検索しdescription、このようなものをこのようcountsなものに変換して挿入することになっています。[a,b,c][(a,9),(b,4),(c,0)]


編集

parsed と counts をテーブルとして、tokenin counts をインデックスにすると、次のようになります。

explain INSERT INTO table (name, mid, description) SELECT name, mid, ARRAY(SELECT ROW(token, count)::a FROM (SELECT token, (SELECT count FROM counts WHERE a.token=counts.token) FROM UNNEST(description) a(token)) _)::a[] description FROM parsed;
                                              QUERY PLAN                                              
------------------------------------------------------------------------------------------------------
 Insert on table  (cost=0.00..5761751808.75 rows=4002061 width=721)
   ->  Seq Scan on parsed  (cost=0.00..5761751808.75 rows=4002061 width=721)
         SubPlan 2
           ->  Function Scan on unnest a  (cost=0.00..1439.59 rows=100 width=32)
                 SubPlan 1
                   ->  Index Scan using counts_token_idx on counts  (cost=0.00..14.39 rows=1 width=4)
                         Index Cond: (a.token = token)

これははるかに合理的です。配列には平均 57 個の要素があるため、パフォーマンスを低下させていたのは、おそらくかなり非効率的な CTE テーブルに対する膨大な数のルックアップだったと思います。現在は毎秒 300 行で、満足しています。

4

2 に答える 2

2

質問に対する私の編集で述べたように、解析されたカウントとテーブルとしてのカウント、およびインデックス化されたカウントのトークンを使用すると、はるかに高速になります。私は、CTE 結合が実際よりも賢いと想定していました。

于 2012-11-05T08:47:28.673 に答える
1

つまり、4Mアレイのネストを解除して再グループ化していますよね?

私の推測では、RAMの枯渇に対処しているので、いくつかの選択肢があると思います。1つは、この問題を最小限に抑えるために、テーブル間でデータを段階的に移動することです。

CPUバウンドなのかI/Oバウンドなのかわかりますか?

于 2012-10-12T02:13:45.290 に答える