我有一个sql查询,在不使用变量时大约一秒运行,如:
WHERE id BETWEEN 5461094 and 5461097
但是当我有:
declare @firstId int
declare @lastId int
set @firstId = 5461094
set @lastId = 5461097
...
WHERE id BETWEEN @firstId and @lastId
...查询运行速度很慢,仅在几分钟后完成。为什么会这样?我需要使用变量。我可以做任何改进以避免这种性能问题吗?
答案 0 :(得分:24)
好的,
我的查询是去图书馆并获取3到5之间的所有书籍
你选择一辆正确,快速,便宜,高效且足以携带3本书的自行车。
新查询。
进入图书馆,获取@x和@y之间的所有书籍。
选择车辆。
继续。
这就是发生的事情。如果我要求1和Maxvalue之间的书籍,你会选择自卸卡车吗?如果x = 3且y = 5,那就太过分了。 SQL必须在看到数字之前选择计划。
答案 1 :(得分:11)
这是因为当值被硬编码时,它可以查找它对表中数据的the statistics,并找出要运行的最佳查询。查看每个查询的执行计划。使用变量时必须扫描。
如果范围总是很小,您可以使用索引提示来帮助解决这个问题。
答案 2 :(得分:3)
有趣的是,这段代码也很快:
DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT * FROM table_x WHERE id BETWEEN ' + CAST(@firstId AS VARCHAR) + ' AND ' + CAST(@lastId AS VARCHAR)
EXEC (@sql)
(MSSQL 2000)
答案 3 :(得分:3)
如果这些变量是存储过程的输入变量,则可能会遇到参数嗅探的问题。 http://omnibuzz-sql.blogspot.com/2006/11/parameter-sniffing-stored-procedures.html
答案 4 :(得分:1)
看起来这个查询与存储过程有关,它的执行计划将在第一次执行proc时被编译,然后重新用于后续执行。
编译的计划可能对于第一次真正接近lastid的情况非常糟糕,但是当价值相差很远时,它真的很好。
尝试在存储过程中启用WITH RECOMPILE选项。如果它解决了问题,并且您对每次执行时重新编译的proc感到满意(您将获得性能损失),请将其留在那里。如果您对性能仍然不满意,请考虑重新设计proc,这样就不需要重新编译了。
答案 5 :(得分:0)
索引中的ID(例如主键)?如果没有,请尝试添加一个。
另一件事可能是在第一个(快速)实例中,查询的执行略有不同。我见过的最常见的事情是连接以低效的顺序完成。尝试重新排序连接,或将一些连接转换为子查询。如果您发布更多查询,我们可以进一步提供帮助。
答案 6 :(得分:0)
实际上,答案非常好,我只是在这里写一个解决方法,因为它对我有用:
使用SQL
创建存储过程WHERE id BETWEEN @firstId and @lastId
然后使用参数@firstId和@lastId调用存储过程,它将加速。我仍然没有100%为什么它正在工作,但它的工作原理。