2017-01-26 3 views
2

Diese Abfrage (SQL2012) Ausführungsplan zeigt mir, dass Clustered Index Scan in der internen Unter Abfrage auf PK Index verwendet:Warum Clustered Index In dieser Suchanfrage scannen?

SELECT n3.id as node_id,x.id as id, 
    (select xv.value from xv 
    --with(forceseek) 
    where xv.id=x.id) as [value] 
    FROM x 
    INNER JOIN n3 
    ON x.[obj_id]=n3.id 
    AND n3.parent_id = '975422E0-5630-4545-8CF7-062D7DF72B6B' 

Die Tabellen x und xv sind Master-> Details Tabellen.

Wenn ich den Hinweis forceseek verwende, dann zeigt es Clustered Index Seek und die Abfrage wird schnell ausgeführt. Warum gibt es Scan statt Seek? Wie ändern Sie die Abfrage, um Index Seek ohne den Hinweis FORCESEEK zu haben?

UPD: Der vollständige Demo-Skript:

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 
/* 
DROP TABLE [dbo].[xv] 
DROP TABLE [dbo].[x] 
DROP TABLE [dbo].[n3] 
*/ 

CREATE TABLE [dbo].[n3](
    [id] [uniqueidentifier] NOT NULL, 
    [parent_id] [uniqueidentifier] NOT NULL, 
CONSTRAINT [PK_n3] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
) 
) 

GO 

CREATE TABLE [dbo].[x](
    [obj_id] [uniqueidentifier] NOT NULL, 
    [id] [int] IDENTITY(1,1) NOT NULL, 
CONSTRAINT [PK_x] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)) 

GO 

ALTER TABLE [dbo].[x] WITH CHECK ADD CONSTRAINT [FK_x_n3] FOREIGN KEY([obj_id]) 
REFERENCES [dbo].[n3] ([id]) 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[x] CHECK CONSTRAINT [FK_x_n3] 
GO 

CREATE TABLE [dbo].[xv](
    [id] [int] NOT NULL, 
    [value] [sql_variant] NOT NULL, 
CONSTRAINT [PK_xv] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)) 

GO 

ALTER TABLE [dbo].[xv] WITH CHECK ADD CONSTRAINT [FK_xv_x] FOREIGN KEY([id]) 
REFERENCES [dbo].[x] ([id]) 
ON DELETE CASCADE 
GO 

ALTER TABLE [dbo].[xv] CHECK CONSTRAINT [FK_xv_x] 
GO 

INSERT INTO n3(id,parent_id) 
select newid(), '975422E0-5630-4545-8CF7-062D7DF72B6B' 
GO 10 

INSERT INTO n3(id,parent_id) 
select newid(), '805422E0-5630-4545-8CF7-062D7DF72B6B' 
GO 5 

INSERT INTO x([obj_id]) 
select id from n3 where parent_id='975422E0-5630-4545-8CF7-062D7DF72B6B'; 


insert into xv (id, value) 
select id, cast(RAND(1) as sql_variant) from x 

--select * from x 
--select * from n3 

    SELECT n3.id as node_id,x.id as id, 
    (select xv.value from dbo.xv 
    --with(forceseek) 
    where xv.id=x.id 
) as [value] 
    FROM dbo.x 
    INNER JOIN dbo.n3 
    ON x.[obj_id]=n3.id 
    AND n3.parent_id = '975422E0-5630-4545-8CF7-062D7DF72B6B' 


/* 
DROP TABLE [dbo].[xv] 
DROP TABLE [dbo].[x] 
DROP TABLE [dbo].[n3] 
*/ 

--Update statistics xv with fullscan 
+0

Wenn Sie mit jeder Zeile in der Tabelle interagieren, würde ich mir vorstellen, dass der Abfrageoptimierer einen Scan über eine Suche verwenden würde. Wenn Sie die Abfrage kopieren und einfügen und beides ausführen, eins mit der Forceseek und eins ohne es, sehen Sie, dass die relativen Kosten des Scans niedriger sind. – dfundako

+0

Es gibt 10 * Millionen Zeilen in realen Tabellen. Mein Problem ist, dass die eigentliche Abfrage (Scan) 3-5 Sekunden ausführt und der Grund für Deadlocks ist. Wenn ich den Hinweis FORCESEEK verwende, funktioniert es <1 Sek. Und Deadlocks sind verschwunden. – Oleg

Antwort

1

Ich vermute, die statistics von xv Tabelle veraltet sein könnten. Aktualisieren Sie die Statistik von xv, und versuchen Sie erneut, die Abfrage auszuführen.

Update statistics xv with fullscan 

Update:

Nachdem bei dem Daten-Setup und Abfrage suchte, für den gegebenen parent_id Eingang ist es ganz klar, dass alle Datensätze in beide x und xv Spiel so offensichtlich ist, dass Optimierer wählt Index statt scan suchen, weil es alle Datensätze aus beiden x und xv Tabelle ist

auch die Anzahl der Datensätze hat holen weniger so wird Optimierer scannen bevorzugen statt suchen

+0

Ich habe es versucht - keine Änderungen. Ich habe das vollständige Demo-Skript hinzugefügt (siehe die erste Nachricht), das dies auf den 3 neuen Tabellen gezeigt hat. – Oleg

+0

@Oleg - Überprüfen Sie das Update –

+0

Bitte beachten Sie meinen Kommentar oben. – Oleg

Verwandte Themen