web-dev-qa-db-ja.com

サブクエリでのcount(*)のパフォーマンス

次のクエリがあるとします。

1。

    SELECT COUNT(*) FROM some_big_table WHERE some_col = 'some_val'

2。

    SELECT COUNT(*) FROM ( SELECT * FROM some_big_table WHERE some_col = 'some_val' )

以前のクエリのいずれかがより優れていますか?それとも同じですか?

Postgresql 9.4を使用していますが、他のDBMSと大きな違いはありますか?

PS:私はこの質問をしています。SQLAlchemy、PythonベースのORM)は、デフォルトでサブクエリに対してCOUNT操作を実行しますが、強制的に実行するオプションがあります。クエリで直接COUNTを使用します。

3
McSonk

彼らが異なるパフォーマンスをすると信じる理由はありますか?もしそうなら、なぜそれらをあなたのRDBMSでそしてあなたのデータでテストしないのですか?一般に、私は最も単純なクエリから始めてパフォーマンスをテストし、必要に応じて(オプション2などの)より複雑なものだけを試すと言います。

RDBMSをリストしていないので、SQL Serverの例を示します。 SQL Serverクエリオプティマイザーは、作成したSQLと直接連携しません。最適化のために内部形式に変換します。次の画像は、最適化のさまざまなフェーズを示しており、Paul Whiteによって Query Optimizer Deep Dive-Part 1 から借用されています。

enter image description here

公開されているAdventure Works 2014データベースに対する私のテストクエリを次に示します。

SELECT COUNT(*) 
FROM Sales.SalesOrderDetail 
WHERE CarrierTrackingNUmber = '2E53-4802-85'

文書化されていないトレースフラグ8606を使用して簡略化した後、クエリツリーの表現を取得できます。

*** Simplified Tree: ***
        LogOp_GbAgg OUT(COL: Expr1002 ,)

            LogOp_Select

                LogOp_Get TBL: Sales.SalesOrderDetail Sales.SalesOrderDetail TableID=1154103152 TableReferenceID=0 IsRow: COL: IsBaseRow1000 

                ScaOp_Comp x_cmpEq

                    ScaOp_Identifier QCOL: [AdventureWorks2014].[Sales].[SalesOrderDetail].CarrierTrackingNumber

                    ScaOp_Const TI(nvarchar collate 872468488,Var,Trim,ML=24) XVAR(nvarchar,Owned,Value=Len,Data = (24,506953514552564850455653))

            AncOp_PrjList 

                AncOp_PrjEl COL: Expr1002 

                    ScaOp_AggFunc stopCount

                        ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=0)

上記はクエリプランの内部表現です。ここでは、クエリプランの実際の手順は重要ではありません。重要なのは、このクエリに対してまったく同じ単純化されたツリーを取得することです。

SELECT COUNT(*) 
FROM 
(
    SELECT * 
    FROM Sales.SalesOrderDetail 
    WHERE CarrierTrackingNUmber = '2E53-4802-85'
) t;

つまり、SQL Serverは、最適化を続行する前に、これら2つのクエリをまったく同じものに書き換えます。これは、2つの間にパフォーマンスの違いがないことを意味します。予想どおり、これらのクエリプランはまったく同じです。

query plan

8
Joe Obbish

この合理的に簡略化された例では、合理的に最新のクエリオプティマイザーは、両方のバリエーションを同じクエリとして理解する必要があります。構造化クエリ言語は手続き型ではなく、宣言型です。宣言型言語は、結果を取得するhowではなく、望ましい結果を記述します。

これを自分で確認できます。両方のクエリを実行し、各バリアントのクエリプロセッサのアクションプランを調べて、yourシステムが実際に実行する方法を確認するのは非常に簡単です。

私はSQL Serverを使用していますが、これをチェックするのに適度なサイズのテーブルがあります。 SSMSを使用して、[クエリ]メニューから[実際の実行プランを含める]を選択して実行しました。

SELECT COUNT(*) FROM dbo.Searchable;
SELECT COUNT(*) FROM (SELECT * FROM dbo.Searchable) st;

計画:

enter image description here

上記のように、PostgreSQLを含むほぼすべての主要なDBMSは、実行計画を検査するためのメカニズムを提供します。

5
Max Vernon

Postgresでのセットアップのテスト:

create table data (id integer, some_value integer);
insert into data
select i, i % 10
from generate_series(1,1000000) i;

create index on data (some_value);
analyze data;

したがって、100万行のテーブルとsome_valueの10個の異なる値があるので、some_value = 9のような条件は100000行を選択します。

explain (analyze,verbose)
select count(*)
from data
where some_value = 9;

私たちに与える:

Aggregate  (cost=7761.13..7761.14 rows=1 width=8) (actual time=16.790..16.791 rows=1 loops=1)
  Output: count(*)
  ->  Bitmap Heap Scan on stuff.data  (cost=1854.13..7514.13 rows=98800 width=0) (actual time=4.703..14.001 rows=100000 loops=1)
        Output: id, some_value
        Recheck Cond: (data.some_value = 9)
        Heap Blocks: exact=4425
        ->  Bitmap Index Scan on data_some_value_idx  (cost=0.00..1829.43 rows=98800 width=0) (actual time=4.243..4.243 rows=100000 loops=1)
              Index Cond: (data.some_value = 9)
Planning time: 0.101 ms
Execution time: 16.876 ms

そして:

explain (analyze,verbose)
select count(*)
from (
  select *
  from data
  where some_value = 9
) x;

これを示しています:

Aggregate  (cost=7761.13..7761.14 rows=1 width=8) (actual time=16.947..16.947 rows=1 loops=1)
  Output: count(*)
  ->  Bitmap Heap Scan on stuff.data  (cost=1854.13..7514.13 rows=98800 width=0) (actual time=4.816..14.173 rows=100000 loops=1)
        Output: data.id, data.some_value
        Recheck Cond: (data.some_value = 9)
        Heap Blocks: exact=4425
        ->  Bitmap Index Scan on data_some_value_idx  (cost=0.00..1829.43 rows=98800 width=0) (actual time=4.332..4.332 rows=100000 loops=1)
              Index Cond: (data.some_value = 9)
Planning time: 0.071 ms
Execution time: 17.032 ms

ご覧のとおり:同一のプランと基本的に同一のランタイム

インデックスがない場合も、同じ実行プランを取得します。

Aggregate  (cost=17180.83..17180.84 rows=1 width=8) (actual time=67.336..67.336 rows=1 loops=1)
  Output: count(*)
  ->  Seq Scan on stuff.data  (cost=0.00..16925.00 rows=102333 width=0) (actual time=0.015..63.878 rows=100000 loops=1)
        Output: id, some_value
        Filter: (data.some_value = 9)
        Rows Removed by Filter: 900000
Planning time: 0.046 ms
Execution time: 67.358 ms
Aggregate  (cost=17180.83..17180.84 rows=1 width=8) (actual time=68.316..68.316 rows=1 loops=1)
  Output: count(*)
  ->  Seq Scan on stuff.data  (cost=0.00..16925.00 rows=102333 width=0) (actual time=0.014..64.848 rows=100000 loops=1)
        Output: data.id, data.some_value
        Filter: (data.some_value = 9)
        Rows Removed by Filter: 900000
Planning time: 0.046 ms
Execution time: 68.336 ms