Ich frage mich, warum SQL Server in einem so einfachen Fall falsche Schätzungen vornimmt. Es gibt ein Szenario.
CREATE PARTITION FUNCTION PF_Test (int) AS RANGE RIGHT
FOR VALUES (20140801, 20140802, 20140803)
CREATE PARTITION SCHEME PS_Test AS PARTITION PF_Test ALL TO ([Primary])
CREATE TABLE A
(
DateKey int not null,
Type int not null,
constraint PK_A primary key (DateKey, Type) on PS_Test(DateKey)
)
INSERT INTO A (DateKey, Type)
SELECT
DateKey = N1.n + 20140801,
Type = N2.n + 1
FROM dbo.Numbers N1
cross join dbo.Numbers N2
WHERE N1.n BETWEEN 0 AND 2
and N2.n BETWEEN 0 AND 10000 - 1
UPDATE STATISTICS A (PK_A) WITH FULLSCAN, INCREMENTAL = ON
CREATE TABLE B
(
DateKey int not null,
SubType int not null,
Type int not null,
constraint PK_B primary key (DateKey, SubType) on PS_Test(DateKey)
)
INSERT INTO B (DateKey, SubType, Type)
SELECT
DateKey,
SubType = Type * 10000 + N.n,
Type
FROM A
cross join dbo.Numbers N
WHERE N.n BETWEEN 1 AND 10
UPDATE STATISTICS B (PK_B) WITH FULLSCAN, INCREMENTAL = ON
Die Einrichtung ist also ziemlich einfach, Statistiken sind vorhanden und SQL Server kann korrekte Schätzungen erstellen, wenn wir eine Tabelle abfragen.
select COUNT(*) from A where DateKey = 20140802
--10000
select COUNT(*) from B where DateKey = 20140802
--100000
Aber in dieser einfachen Auswahl sind Schätzungen weit entfernt, und ich sehe keine Erklärung dafür.
SELECT a.DateKey, a.Type
FROM A
JOIN B
ON b.DateKey = a.DateKey
AND b.Type = a.Type
WHERE a.DateKey = 20140802
Unmittelbar nach der Clustered Index-Suche liegt die Schätzung bei 57% vom tatsächlichen Wert! Die reale Abfrage ist noch schlimmer, die Schätzung liegt bei 2% vom tatsächlichen Wert.
PS-Nummerntabelle zur Reproduktion des Setups
DECLARE @UpperBound INT = 1000000;
;WITH cteN(Number) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id]) - 1
FROM sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
)
SELECT n = [Number] INTO dbo.Numbers
FROM cteN WHERE [Number] <= @UpperBound;
CREATE UNIQUE CLUSTERED INDEX CIX_Number ON dbo.Numbers(n)
WITH
(
FILLFACTOR = 100, -- in the event server default has been changed
DATA_COMPRESSION = ROW -- if Enterprise & table large enough to matter
);
PPS Das gleiche Szenario, jedoch nicht partitioniert, funktioniert einwandfrei.