I have made an example to allow me to show what my issue is:
Setup:
CREATE TABLE [dbo].[Test](
[TestId] [bigint] IDENTITY(1,1) NOT NULL,
[ParentTestId] [bigint] NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ([TestId] ASC)
)
GO
ALTER TABLE [dbo].[Test] WITH CHECK ADD CONSTRAINT [FK_Test_ParentTest]
FOREIGN KEY([ParentTestId])
REFERENCES [dbo].[Test] ([TestId])
GO
ALTER TABLE [dbo].[Test] CHECK CONSTRAINT [FK_Test_ParentTest]
GO
DECLARE @iter INT
SET @iter = 1
WHILE @iter < 1000
BEGIN
INSERT INTO dbo.Test ( ParentTestId )
VALUES ( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),
( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null ),( null )
SET @iter = @iter + 1
END
go
This creates a self referencing table and adds over 40,000 rows to it.
Action:
DELETE FROM dbo.Test WHERE TestId = 200
I then want to delete a row from this table. If you turn on the actual query plan and run the above statement you can see that 20% of the cost is taken in a Clustered Index Scan for the self referencing key.
This is not a big deal in this scenario, but my real scenario has over 25 million rows in a large table.
So, I have two questions:
- Why is it doing an Index Scan? It has a Primary Key/Clustered Index value. Why would it not do a Index Seek?
- How can I make it do an Index Seek? (It is taking about 1 min to delete a row.)
Edit: I thought that this could be due SQL Server looking to see if other rows were referencing the one I was deleting. But I set "Enforce Foreign Key Constraint" to "No" and it still took the same cost do a clustered index scan.