我有一个包含此内容的查询:
... AND Record.RecordID IN (1,2,3,10,11,12,13,16,17,18,26,27,28,557,31,32,33,36,37,93) AND ...
问题似乎是如果该列表中有20个或更多项,则查询执行时间超过25秒。如果少于20,则立即执行。关于如何优化的任何想法?
答案 0 :(得分:9)
要做的一件事就是查看优化程序计划(如果可以的话)并查看当您使用20项或更少项目与>时计划的不同之处20.例如,在Oracle中,您可以使用explain plan命令查看此输出。
以下是有关如何在Oracle中使用解释计划的一些信息: http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/ex_plan.htm
要考虑的其他事项是您是否在RecordID上有索引。可能是一旦你越过某个阈值(在你的情况下大约20个项目),优化器就会决定使用全表扫描而不是使用你的索引。
有时,对于某些数据库,您可以使用优化程序提示来说服优化程序使用索引,如果这确实可以带来更好的性能。
以下是您可以阅读的优化程序提示的链接: http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/hintsref.htm
我的回答是以Oracle为中心的,但同样的原则应该适用于大多数数据库。
答案 1 :(得分:9)
将RecordID放在临时表中,并使用inner join
对其进行过滤。对于SQL Server,这看起来像:
declare @RecordIds table (int RecordID)
insert into @RecordIds values (1)
insert into @RecordIds values (2)
...
insert into @RecordIds values (93)
select r.*
from Records r
inner join @RecordIds ri on ri.RecordID = r.RecordID
答案 2 :(得分:2)
第20项恰好将这个特定查询成本估算的平衡从一个计划转移到另一个计划。有20个项目你可能会得到一个全表扫描。 IN只是OR的语法糖.. OR ... OR ... OR。而OR是良好查询计划的敌人。正如Andomar建议的那样使用联接。
<强>更新强>
如果您退出IN语法,您还可以使用query plan hint并确保查询保持最佳计划。 IN语法强制您在每次执行时更改查询,因此您无法使用查询计划提示。
答案 3 :(得分:0)
看起来很脏而且没必要,但你试过了吗?
(Record.RecordID IN (--19 items--) OR Record.RecordID = 20th_item) AND
我不知道为什么将第20个项目添加到IN
组会将其推到边缘。
答案 4 :(得分:0)
对于MySQL,manual说“IN列表中的值的数量仅受max_allowed_packet值的限制。”这似乎不太可能是问题,但它是一个值得关注的地方
无论如何,将IN()
值存储在临时表中并将查询加入其中应该可以解决整个问题。
答案 5 :(得分:0)
CLR表值函数将是根据提供的参数创建表的另一种方法 - 有关详细信息,请参阅SQL Server 2005: CLR Table-Valued Functions
答案 6 :(得分:0)
似乎在添加第20项时,优化程序会生成不同的执行计划。执行计划是基于统计数据构建的。搜索条件会影响预期的结果行。在条件列表中添加更多项目时,预期返回的行会更改,优化程序可能会生成新的执行计划。
检查两个查询的执行计划(CTRL-L)。这是了解为什么在列表中有超过20个项目需要更多时间的唯一方法。
在检查执行计划之前,请更新表的统计信息:
UPDATE STATISTICS records
如果你可以等待
UPDATE STATISTICS records WITH FULLSCAN
第二个将花费更多时间,但您将获得更一致的统计数据。