直到今天,我认为我已经掌握了通过子查询上的连接来优化查询的诀窍。但我一直在尝试优化查询,一时兴起,我尝试了一种我认为不再需要使用的旧方法——我使用了临时表。
慢查询(需要 5 分钟)...
select (columns) from big_transactions_table t inner join
(select (columns) from small_info_table where (conditions)) q1
on q1.key = t.key
group by (columns)
使用临时表进行快速查询...
select (columns) from small_info_table into #q1 where (conditions)
go
select (columns) from big_transactions_table t inner join #q1
on #q1.key = t.key
group by (columns)
花了14秒!
我的印象是,当您在这样的连接中有一个子查询时,SQL 引擎会先获取数据,然后再将其与外部查询连接起来。现在我不太确定。谁能告诉我为什么执行时间会有很大差异,以及是否有一种不使用临时表来加速查询的简单方法?
查询优化器考虑各种物理执行策略,保证产生与原始逻辑查询规范相同的结果。所以,不,您无法从查询的书面形式中得出关于它将如何实际执行的一般性推断。
优化器做出的决定基于估计的成本,这在很大程度上取决于管道每个阶段预期的数据大小(基数和宽度)以及执行的物理操作的类型。
如果您的查询恰好导致成本估算不准确,则优化器选择的策略很可能不是最优的,甚至可能根本不是很好。
不准确的成本有很多原因,包括对基本对象的不具代表性的统计,以及在查询中使用不透明或难以估计的谓词。有了良好的统计数据、合理大小的查询、简单的比较操作和关系模式,估计(以及因此优化器的物理计划选择)至少足够好的可能性很大。
简化优化器工作的一种方法是将复杂查询(或根本无法获得良好估计的查询)的一部分具体化到临时表中。这些为优化器提供了直接的基数信息,SQL Server 通常可以自动在临时表上创建统计信息以提供进一步的有用信息。最后但并非最不重要的一点是,临时表允许您向其中添加特定的索引,这是值得的。
如果使用得当*,临时表是向优化器提供信息的好方法,即使底层数据的分布和大小发生变化也能生成可靠的执行计划。
如果您已经完成了统计、索引和查询的书面形式,那么在这里使用临时表可能是最佳选择。根据问题中提供的信息,并且不知道作者的专业水平,不可能肯定地说。
* 合理使用意味着限制所需临时表的数量、大小和宽度,以及使用频率。
SELECT * INTO #temp FROM dbo.MyHugeTable;
例如,这是不明智的。