次のクエリがあるとします。
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
を使用します。
彼らが異なるパフォーマンスをすると信じる理由はありますか?もしそうなら、なぜそれらをあなたのRDBMSでそしてあなたのデータでテストしないのですか?一般に、私は最も単純なクエリから始めてパフォーマンスをテストし、必要に応じて(オプション2などの)より複雑なものだけを試すと言います。
RDBMSをリストしていないので、SQL Serverの例を示します。 SQL Serverクエリオプティマイザーは、作成したSQLと直接連携しません。最適化のために内部形式に変換します。次の画像は、最適化のさまざまなフェーズを示しており、Paul Whiteによって Query Optimizer Deep Dive-Part 1 から借用されています。
公開されている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つの間にパフォーマンスの違いがないことを意味します。予想どおり、これらのクエリプランはまったく同じです。
この合理的に簡略化された例では、合理的に最新のクエリオプティマイザーは、両方のバリエーションを同じクエリとして理解する必要があります。構造化クエリ言語は手続き型ではなく、宣言型です。宣言型言語は、結果を取得するhowではなく、望ましい結果を記述します。
これを自分で確認できます。両方のクエリを実行し、各バリアントのクエリプロセッサのアクションプランを調べて、yourシステムが実際に実行する方法を確認するのは非常に簡単です。
私はSQL Serverを使用していますが、これをチェックするのに適度なサイズのテーブルがあります。 SSMSを使用して、[クエリ]メニューから[実際の実行プランを含める]を選択して実行しました。
SELECT COUNT(*) FROM dbo.Searchable;
SELECT COUNT(*) FROM (SELECT * FROM dbo.Searchable) st;
計画:
上記のように、PostgreSQLを含むほぼすべての主要なDBMSは、実行計画を検査するためのメカニズムを提供します。
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