【问题标题】:Why is there a HUGE performance difference between temp table and subselect为什么临时表和子选择之间存在巨大的性能差异
【发布时间】:2013-05-21 23:36:37
【问题描述】:

这是一个关于 SQL Server 2008 R2 的问题

到目前为止,我还不是 DBA。我是一名java开发人员,时不时要写SQL。 (主要嵌入在代码中)。我想知道我是否在这里做错了什么,如果是,我能做些什么来避免它再次发生。

第一季度:

SELECT something FROM (SELECT * FROM T1 WHERE condition1) JOIN ...

第一季度有 14 个连接

Q2 与 Q1 相同,但有一个例外。 (SELECT * FROM T1 WHERE condition1) 之前执行,并存储在临时表中。

这不是相关的子查询。

第二季度:

SELECT * INTO #tempTable FROM T1 WHERE condition1
SELECT something FROM #tempTable  JOIN ...

再次,14 个连接。

现在让我感到困惑的是,Q1 花了 > 2 分钟,(尝试了几次,以避免缓存发挥作用)而 Q2(两个查询相结合)花了 2 秒!!!什么给了?

【问题讨论】:

  • 我的猜测是SELECT * FROM T1 WHERE condition1 的估计行数非常不准确。将其具体化为 #tempTable 意味着 SQL Server 确切知道将返回多少行。你能发布两个实际执行计划的 XML 版本吗?

标签: sql sql-server-2008-r2 subquery query-performance temp-tables


【解决方案1】:

为什么不推荐使用子查询?

数据库优化器(无论您使用什么数据库)不能始终正确优化此类查询(带有子查询)。在这种情况下,优化器的问题是选择正确的方法来连接结果集。有几种算法可以连接两个结果集。算法的选择取决于包含在一个结果集中和另一个结果集中的记录数。如果连接两个物理表(子查询不是物理表),数据库可以通过可用的统计数据轻松确定两个结果集中的数据量。如果其中一个结果集是子查询,那么要了解它返回多少条记录是非常困难的。在这种情况下,数据库可能会选择错误的join查询计划,从而导致查询性能急剧下降。

使用临时表重写查询旨在简化数据库优化器。在重写查询中,参与连接的所有结果集都是物理表,数据库将轻松确定每个结果集的长度。这将允许数据库选择所有可能的查询计划中保证最快的。而且,无论条件如何,数据库都会做出正确的选择。使用临时表重写的查询在任何数据库上都可以很好地工作,这在开发可移植解决方案中尤其重要。此外,重写后的查询更易于阅读、更易于理解和调试。

据了解,使用临时表重写查询可能会由于额外费用而导致速度变慢:创建临时表。如果数据库在查询计划的选择上不会出错,它将比新查询更快地执行旧查询。然而,这种放缓总是可以忽略不计。通常,临时表的创建需要几毫秒。即延迟不会对系统性能产生重大影响,通常可以忽略。

重要!不要忘记为临时表创建索引。索引字段应包括连接条件中使用的所有字段。

【讨论】:

  • SQL Server 查询引擎在内部创建临时表,您上面提供的原因并不总是正确的。它取决于更多其他因素,如索引、碎片、统计等。
  • 在临时表上创建索引可以提高查询性能。
  • 您的回答非常具有误导性和错误性,仅应在某些情况下考虑创建临时表:stackoverflow.com/questions/42772428/…
  • @Arvand 。 . .这不是“错误的”,尽管我不同意这个建议。如果您仔细阅读,我和 Karthik 都建议在临时表上使用索引来提高性能。根据我的经验,问题几乎总是嵌套循环连接,并且可以通过查询提示来避免这些问题。我发现查询提示比许多临时表更容易维护。
  • @GordonLinoff 第一段和第二段的结论是子查询应该用临时表重写,因为:“数据库可以通过可用的统计数据轻松确定两个结果集中的数据量”,即错误的假设并可能导致错误的结论。
【解决方案2】:

这里有很多事情要处理,索引、执行计划等。测试和比较结果是要走的路。

您可以查看通常的嫌疑人索引。查看执行计划并进行比较。确保 WHERE 子句使用正确的子句。确保您使用的是 JOINs 上的索引。

这些答案肯定会对你有很大帮助。

【讨论】:

    猜你喜欢
    • 2014-10-29
    • 2018-08-29
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多