【发布时间】:2019-06-16 07:14:26
【问题描述】:
我有 2 张桌子:a 和 b。表a 有大约100 万条记录,而表b 有大约50,000 条记录。非聚集索引在 a 和 b 中的每个列上定义。这 2 个表是基于这些列连接的。查询如下:
SELECT * INTO x
FROM a JOIN b ON a.cola = b.colb
最终结果是大约 200 万条记录。查询大约需要 14 分钟才能完成。但是,如果我尝试使用COUNT(*) 而不是SELECT...INTO,则查询不到一分钟即可完成。
SELECT COUNT(*)
FROM a JOIN b ON a.col1 = b.col1
我假设剩下的 13 分钟是由于 I/O 操作。所以我运行了另一个查询,它刚刚从“x”中获取先前插入的数据并插入到“y”中。
SELECT * INTO y
FROM x
此查询需要 5 分钟来插入 200 万行数据。那么我的问题是第一个查询需要 14 分钟才能完成的原因是什么,而实际连接和独立插入同一组数据的总时间仅为 6 分钟。剩余8分钟的执行时间是什么原因?有什么办法可以减少这个时间吗?
我查看了第一个查询的实际执行计划。 > 95% 的时间都用在了 INSERT 操作中。 INSERT 操作只是按原样插入列 - 没有其他逻辑(如计算、CAST、CASE...WHEN 等)。我的数据库已经处于 BULK_LOGGED 恢复模式,因此这些 SELECT...INTO 操作的日志记录最少。
【问题讨论】:
-
因为,
SELECT * INTO xSQL Server 需要为 每一 行获取 每一 列的值,对于SELECT COUNT(*)它只需要知道有多少行。它们是完全不同的查询。想象一下,如果我让你计算一本书有多少页,并且我还让你逐页复制该书的全部内容;你真的认为你可以同时做到快/慢吗? -
假设 估计成本的 95% = 时间的 95% 是错误的。这只是对 I/O 和 CPU 成本的估计。操作过程中有哪些等待类型?您如何确认您获得的日志记录最少?这不仅仅取决于数据库恢复模型。
标签: sql sql-server sql-server-2012 query-optimization database-performance