web-dev-qa-db-ja.com

クエリがすべてのパーティションをスキャンするのはなぜですか?

次の分割テーブルがあります

create table T (Month char(6), ID int, .... primary key (ID, Month)) on psMonth(Month)

パーティション関数は

CREATE PARTITION FUNCTION [pfMonth](char(6)) AS 
RANGE RIGHT FOR VALUES (N'200001', .... N'200705', N'200706', N'200707', ....)

ただし、次のクエリが示す実際のパーティション数は、1ではなく260ですか?

select count(*)
from T (nolock)
where Month = '200706'

実行計画は

 | --Compute Scalar(DEFINE:([Expr1004] = CONVERT_IMPLICIT(int、[globalagg1006]、0)))
 | --Stream Aggregate(DEFINE:([globalagg1006] = SUM( [partialagg1005]))))
 | --Parallelism(Gather Streams)
 | --Stream Aggregate(DEFINE:([partialagg1005] = Count(*)))
 |- -クラスター化インデックススキャン(OBJECT:([DB]。[dbo]。[T]。[PK_T])、WHERE:([DB]。[dbo]。[T]。[Month] = [@ 1])) 

更新:
次のクエリを実行すると、クエリが高速で実行され、実際のパーティションカウントが1になります。

select count(*), $partition.pfMonth(Month)
from T with (nolock)
where Month = '200706'
group by $partition.pfMonth(Month)

更新2:
次のクエリも1つのパーティションのみをスキャンします。

select count(*), min($partition.pfByMonth(Month))
from T 
where Month = '200707'

更新3:
現在、元のSQLは1つのパーティションのみをスキャンします。何が起こったのかわかりません。唯一の違いは、より多くのデータがテーブルに挿入されていることです。
Answer:テーブルをラップするCTEを使用しました。また、型の優先順位によって引き起こされる問題を回避しました。 (ただし、CTEは最初はこの問題を回避していませんでしたが、全体が奇妙で予測不可能です。)

2
u23432534

列のタイプはCHAR(6)です。フィルターのタイプはVARCHARです(おそらく直感に反しますが、定数リテラル'200706' is)。 Data Type Precedence のルールは、優先順位の高いタイプを使用して比較が行われることを示しています。 VARCHARタイプ。これはパーティショニング機能とはタイプが異なるため、パーティションの削除は行われません。

代わりにこれを試してください:

select count(*)
from T (nolock)
where Month = CAST('200706' as CHAR(6));

計画では、パーティション分割除去フィルターを取得する必要があります。

9
Remus Rusanu

これはあなたの他の質問に直接関連しています

パーティションキーだけにインデックスはありません。これはPKの2番目のキーです。このため、エンジンはすべての行をチェックする必要があります。そのフィールドにインデックスがある場合は、インデックスのみをチェックできます。

2
JNK