在SQL Server 2005上运行两个版本的查询时,我们看到了奇怪的行为:
版本A:
SELECT otherattributes.* FROM listcontacts JOIN otherattributes
ON listcontacts.contactId = otherattributes.contactId WHERE listcontacts.listid = 1234
ORDER BY name ASC
版本B:
DECLARE @Id AS INT;
SET @Id = 1234;
SELECT otherattributes.* FROM listcontacts JOIN otherattributes
ON listcontacts.contactId = otherattributes.contactId
WHERE listcontacts.listid = @Id
ORDER BY name ASC
两个查询都返回1000行;版本A平均需要15秒;版本B平均需要4秒。 任何人都可以帮助我们理解这两个版本的SQL执行时间的差异吗?
如果我们使用NHibernate通过命名参数调用此查询,我们会通过SQL Server探查器看到以下查询:
EXEC sp_executesql N'SELECT otherattributes.* FROM listcontacts JOIN otherattributes ON listcontacts.contactId = otherattributes.contactId WHERE listcontacts.listid = @id ORDER BY name ASC',
N'@id INT',
@id=1234;
......这往往与版本A一样糟糕。
答案 0 :(得分:2)
尝试查看查询的执行计划。这应该为您提供有关如何执行查询的更多解释。
答案 1 :(得分:2)
我没有看到执行计划,但我强烈怀疑它们在这两种情况下是不同的。您遇到的问题是,如果A(更快的查询)优化器知道您用于列表ID(1234)的值,并且使用分布统计信息和索引的组合选择最佳计划。
在第二种情况下,优化器无法嗅探ID的值,因此会产生一个对任何传入的列表ID都可接受的计划。在我说可接受的地方,我并不意味着最佳。
那么你可以做些什么来改善这种情况呢?这里有几种选择:
1)创建存储过程以执行以下查询:
CREATE PROCEDURE Foo @Id INT 如 SELECT otherattributes。* FROM listcontacts JOIN otherattributes ON listcontacts.contactId = otherattributes.contactId WHERE listcontacts.listid = @Id ORDER BY name ASC
GO
这将允许优化器在传入时嗅探输入参数的值,并为第一次执行生成适当的执行计划。不幸的是,它会缓存该计划以便以后再次使用,所以除非您通常使用类似的选择性值调用sproc,否则这可能对您没有多大帮助
2)创建如上所述的存储过程,但将其指定为WITH RECOMPILE。这将确保每次执行时重新编译存储过程,从而生成针对此输入值优化的新计划
3)将OPTION(RECOMPILE)添加到SQL语句的末尾。强制重新编译此语句,并能够针对输入值进行优化
4)将OPTION(OPTIMIZE FOR(@Id = 1234))添加到SQL语句的末尾。这将导致缓存的计划针对此特定输入值进行优化。如果这是一个非常常见的值,或者大多数常见值具有相似的选择性,那就太好了,但如果选择性的分布更广泛地传播,那就不那么好了。
答案 2 :(得分:0)
有可能代替将1234转换为与listcontacts.listid相同的类型,然后与每行进行比较,它可能会将每行中的值转换为与1234相同。第一个只需要一个转换,第二行需要每行一次演员(这可能超过1000行,可能是表格中的每一行)。我不确定该常量将被解释为什么类型,但它可能是'数字'而不是'int'。
如果这是原因,第二个版本更快,因为它强制1234被解释为int,因此无需在每一行中转换值。
但是,正如之前的海报所示,SQL Server Management Studio中显示的查询计划可能表示另一种解释。
答案 3 :(得分:0)
了解正在发生的事情的最好方法是比较执行计划,其他一切都是根据问题中提供的有限细节进行推测。
要查看执行计划,请进入SQL Server Management Studio并运行SET SHOWPLAN_XML ON
然后运行查询版本A,查询将不会运行,但执行计划将以XML格式显示。然后运行查询版本B并查看其执行计划。如果您仍然无法区分或解决问题,请发布执行计划,此处有人会解释。