207

非常に単純な SQL クエリがあります。

SELECT COUNT(DISTINCT x) FROM table;

私のテーブルには約 150 万行あります。このクエリの実行速度はかなり遅いです。約 7.5 秒かかります。

 SELECT COUNT(x) FROM table;

これには約 435ms かかります。クエリを変更してパフォーマンスを向上させる方法はありますか? グループ化して通常のカウントを行い、x にインデックスを付けてみました。どちらも同じ 7.5 秒の実行時間です。

4

4 に答える 4

407

これを使用できます:

SELECT COUNT(*) FROM (SELECT DISTINCT column_name FROM table_name) AS temp;

これは、次のものよりもはるかに高速です。

COUNT(DISTINCT column_name)
于 2013-02-06T15:17:09.610 に答える
13
-- My default settings (this is basically a single-session machine, so work_mem is pretty high)
SET effective_cache_size='2048MB';
SET work_mem='16MB';

\echo original
EXPLAIN ANALYZE
SELECT
        COUNT (distinct val) as aantal
FROM one
        ;

\echo group by+count(*)
EXPLAIN ANALYZE
SELECT
        distinct val
       -- , COUNT(*)
FROM one
GROUP BY val;

\echo with CTE
EXPLAIN ANALYZE
WITH agg AS (
    SELECT distinct val
    FROM one
    GROUP BY val
    )
SELECT COUNT (*) as aantal
FROM agg
        ;

結果:

original                                                      QUERY PLAN                                                      
----------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=36448.06..36448.07 rows=1 width=4) (actual time=1766.472..1766.472 rows=1 loops=1)
   ->  Seq Scan on one  (cost=0.00..32698.45 rows=1499845 width=4) (actual time=31.371..185.914 rows=1499845 loops=1)
 Total runtime: 1766.642 ms
(3 rows)

group by+count(*)
                                                         QUERY PLAN                                                         
----------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=36464.31..36477.31 rows=1300 width=4) (actual time=412.470..412.598 rows=1300 loops=1)
   ->  HashAggregate  (cost=36448.06..36461.06 rows=1300 width=4) (actual time=412.066..412.203 rows=1300 loops=1)
         ->  Seq Scan on one  (cost=0.00..32698.45 rows=1499845 width=4) (actual time=26.134..166.846 rows=1499845 loops=1)
 Total runtime: 412.686 ms
(4 rows)

with CTE
                                                             QUERY PLAN                                                             
------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=36506.56..36506.57 rows=1 width=0) (actual time=408.239..408.239 rows=1 loops=1)
   CTE agg
     ->  HashAggregate  (cost=36464.31..36477.31 rows=1300 width=4) (actual time=407.704..407.847 rows=1300 loops=1)
           ->  HashAggregate  (cost=36448.06..36461.06 rows=1300 width=4) (actual time=407.320..407.467 rows=1300 loops=1)
                 ->  Seq Scan on one  (cost=0.00..32698.45 rows=1499845 width=4) (actual time=24.321..165.256 rows=1499845 loops=1)
       ->  CTE Scan on agg  (cost=0.00..26.00 rows=1300 width=0) (actual time=407.707..408.154 rows=1300 loops=1)
     Total runtime: 408.300 ms
    (7 rows)

CTEの場合と同じ計画は、おそらく他の方法(ウィンドウ関数)によっても作成できます

于 2012-06-28T18:32:27.500 に答える
4

count(distinct(x))がそれよりも大幅に遅い場合は、トリガーを使用するcount(x)などして、別のテーブルで x 値のカウントを維持することにより、このクエリを高速化できます。table_name_x_counts (x integer not null, x_count int not null)ただし、書き込みパフォーマンスは低下し、単一のトランザクションで複数の値を更新するx場合は、デッドロックの可能性を回避するために明示的な順序でこれを行う必要があります。

于 2012-06-30T18:21:16.243 に答える