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
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
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