我有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中使用直接值与变量,并且两者都返回相同的结果。 为什么查询执行计划在使用直接值与变量之间发生变化?
答案 0 :(得分:1)
我认为这个问题很可能是通过参数嗅探来解释的。 SQL Server通常会识别和缓存常用查询的查询计划。作为这种缓存的一部分,它会嗅探"您在最常见的查询中使用的参数,以优化计划的创建。
查询1显示了一个直接字符串,因此SQL会创建一个特定的计划。查询2使用中间变量,这是实际阻止参数嗅探的技术之一(通常用于为存储的过程或查询提供更可预测的性能,其中参数具有显着的差异。这些被认为是对SQL的两个完全不同的查询,尽管显而易见观察到的差异基本上只是优化。
此外,如果您的表具有不同的行计数分布,那么您可能会基于现有索引和潜在优化与这两个方案存在潜在差异。在没有加载示例数据的服务器上,查询1和查询2具有相同的执行计划,因为优化器无法找到任何更好的参数路径。
了解更多信息:http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx
答案 1 :(得分:0)
以下查询显示类似的计划,但WHERE子句不同。
select Code from OrderItems WHERE Code like '6662225%'
declare @SearchKeyword varchar(200) = '6662225'
select Code from OrderItems WHERE Code like @SearchKeyword + '%'
答案 2 :(得分:0)
以下帖子/答案提供了一个很好的解释,说明为什么硬编码常量的性能比变量更好,以及您可能尝试的一些建议: