SQL服务器查询计划

时间:2015-02-18 01:02:54

标签: sql sql-server

我有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中使用直接值与变量,并且两者都返回相同的结果。 为什么查询执行计划在使用直接值与变量之间发生变化?

3 个答案:

答案 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)

以下帖子/答案提供了一个很好的解释,说明为什么硬编码常量的性能比变量更好,以及您可能尝试的一些建议:

Alternative to using local variables in a where clause