我有3张桌子,如下所示

CREATE TABLE dbo.RootTransaction
    (
    TransactionID int CONSTRAINT [PK_RootTransaction] PRIMARY KEY NONCLUSTERED (TransactionID ASC)
    )

GO
----------------------------------------------------------------------------------------------------

CREATE TABLE [dbo].[OrderDetails](
    [OrderID] int identity(1,1) not null,
    TransactionID int,
    OrderDate datetime,
    [Status] varchar(50)
 CONSTRAINT [PK_OrderDetails] PRIMARY KEY CLUSTERED ([OrderID] ASC),
 CONSTRAINT [FK_TransactionID] FOREIGN KEY ([TransactionID]) REFERENCES [dbo].[RootTransaction] ([TransactionID]),
) ON [PRIMARY]

GO

CREATE NONCLUSTERED INDEX [ix_OrderDetails_TransactionID]
    ON [dbo].[OrderDetails](TransactionID ASC, [OrderID] ASC);

GO
----------------------------------------------------------------------------------------------------
CREATE TABLE dbo.OrderItems
(
    ItemID int identity(1,1) not null,
    [OrderID] int,
    [Name]  VARCHAR (50)  NOT NULL,
    [Code]  VARCHAR (9)   NULL,
    CONSTRAINT [PK_OrderItems] PRIMARY KEY NONCLUSTERED ([ItemID] ASC),
    CONSTRAINT [FK_OrderID] FOREIGN KEY ([OrderID]) REFERENCES [dbo].[OrderDetails] ([OrderID])
)
Go
CREATE CLUSTERED INDEX OrderItems
    ON [dbo].OrderItems([OrderID] ASC, ItemID ASC) WITH (FILLFACTOR = 90);
GO
CREATE NONCLUSTERED INDEX [IX_Code]
    ON [dbo].[OrderItems]([Code] ASC) WITH (FILLFACTOR = 90)
----------------------------------------------------------------------------------------------------

Populated sample data in each table
select COUNT(*) from RootTransaction -- 45851
select COUNT(*) from [OrderDetails] -- 50201
select COUNT(*) from OrderItems --63850
-- Query 1
SELECT  o.TransactionID
FROM [OrderDetails] o
JOIN dbo.OrderItems i ON o.OrderID = i.OrderID
WHERE i.Code like '1067461841%'


declare @SearchKeyword  varchar(200) = '1067461841'

-- Query 2
SELECT  o.TransactionID
FROM [OrderDetails] o
JOIN dbo.OrderItems i ON o.OrderID = i.OrderID
WHERE i.Code like @SearchKeyword + '%'


在上述2个查询上运行时,我可以看到查询1在OrderDetails,OrderItems上使用了索引查找,
但是,在查询2中,查询计划对OrderItems使用索引查找,而对OrderDetails使用索引扫描。
在两个查询中,唯一的区别是在LIKE中使用直接值vs变量,并且两者都返回相同的结果。
为什么查询执行计划在使用直接值与变量之间更改?

最佳答案

我相信最有可能通过参数嗅探来解释该问题。 SQL Server通常会识别并缓存常用查询的查询计划。作为此缓存的一部分,它“嗅探”您在最常见查询中使用的参数,以优化计划的创建。

查询1显示一个直接字符串,因此SQL创建一个特定的计划。查询2使用中间变量,这是实际上防止参数嗅探的技术之一(通常用于为参数有显着差异的存储的proc或查询提供更可预测的性能。尽管有明显的区别,但这些查询被认为是与SQL完全不同的2条查询)所观察到的差异本质上只是优化。

此外,如果您的表具有不同的行数分布,则根据现有索引和潜在的优化,您可能会与这两种方案存在潜在的差异。在没有加载示例数据的服务器上,查询1和查询2具有相同的执行计划,因为优化器找不到任何更好的参数路径。

有关更多信息:http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

关于sql - SQL Server查询计划,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28574171/

10-12 22:56
查看更多