- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
使用sql server 2014; ((SP1-CU3) (KB3094221) 2015 年 10 月 10 日 x64
我有以下查询
SELECT * FROM dbo.table1 t1
LEFT JOIN dbo.table2 t2 ON t2.trade_id = t1.tradeNo
LEFT JOIN dbo.table3 t3 ON t3.TradeReportID = t1.tradeNo
order by t1.tradeNo
order by
此查询在 3 秒内执行,有 73k 行。
LEFT JOIN
的顺序s 有所作为:
SELECT * FROM dbo.table1 t1
LEFT JOIN dbo.table3 t3 ON t3.TradeReportID = t1.tradeNo
LEFT JOIN dbo.table2 t2 ON t2.trade_id = t1.tradeNo
order by t1.tradeNo
t1.tradeNo
和
t2.trade_id
和
t3.TradeReportID
没有效果。
order by
仅使用一个左连接(两种情况)运行查询很快。
LEFT JOIN
的顺序s 但这并不能解释为什么会发生这种情况以及在什么情况下可能会再次发生
order by
子句导致执行计划使用表假脱机(懒惰假脱机)与在快速查询中不使用它。
DBCC RULEOFF ('BuildSpool');
关闭桌面线轴这“修复”了速度,但根据
this post不推荐这样做,无论如何都不能按查询执行此操作
table3.Text
] 的类型为
varchar(max)
) - 如果将其更改为
nvarchar(512)
那么原始(慢)查询现在很快——即执行计划现在决定不使用表假脱机——还要注意,即使类型是
varchar(max)
每一行的字段值都是 NULL。这现在可以解决,但我并不聪明
Type conversion in expression (CONVERT_IMPLICIT(nvarchar(50),[t2].[trade_id],0)) may affect "CardinalityEstimate" in query plan choice, ...
t1.tradeNo
是
nvarchar(21)
- 另外两个是
varchar(50)
- 将后两个更改为与第一个相同后,问题就消失了! (保留 UPDATE 2 中所述的 varchar(max) 不变)
nvarchar(max)
非常有趣没有数据的列。
最佳答案
您可能最好的解决方法是 确保联接的两侧具有相同的数据类型 .没有必要是varchar
和另一个 nvarchar
.
这是 DB 中经常出现的一类问题。数据库是 假设错误 关于它即将处理的数据的组成。估计执行计划中显示的成本可能与实际计划中的成本相差甚远。我们都会犯错误,如果 SQL Server 能从它自己中吸取教训,那真的很好,但目前还没有。尽管一次又一次地被立即证明是错误的,它仍将估计 2 秒的返回时间。公平地说,我不知道有任何 DBMS 有机器学习可以做得更好。
您查询速度快的地方
最难的部分是通过对 table3 进行排序来预先完成的。这意味着它可以进行高效的合并连接,这反过来意味着它没有理由对假脱机感到懒惰。
哪里慢
拥有一个将同一事物存储为两种不同类型和数据长度的 ID 不应该是必要的,并且对于 ID 来说永远不是一个好主意。在这种情况下 nvarchar
一处varchar
在另一个。当这使它无法获得基数估计时,这就是关键缺陷,原因如下:
优化器希望只需要 table3 中的几个唯一行。只有少数选项,如“男”、“女”、“其他”。这就是所谓的“低基数”。所以想象一下,由于某种奇怪的原因,tradeNo 实际上包含性别的 ID。请记住,是您具有情境化的人类技能,谁知道这不太可能。 DB 对此视而不见。所以这是它期望发生的事情:当它第一次遇到“Male”的 ID 时执行查询时,它会懒惰地获取关联的数据(如“Male”一词)并将其放入假脱机中。接下来,因为它已经排序,它只需要更多的雄性,并且简单地重复使用它已经放入线轴的东西。
基本上,它计划在几个大块中从表 1 和 2 中获取数据,并停止一次或两次以从表 3 中获取新的详细信息。实际上,停止并不是偶然的。事实上,它甚至可能在每一行都停止,因为这里有很多不同的 ID。 懒惰的线轴就像上楼一次拿一件小东西 .如果您认为您只需要钱包,那就太好了。如果你搬家就不太好,在这种情况下你会想要一个大盒子(急切的线轴)。
缩小表 3 中字段的大小有所帮助的可能原因是,这意味着它估计在预先进行完整排序时执行惰性假脱机的相对优势较少。与 varchar
它不知道有多少数据,只知道可能有多少。需要改组的潜在数据块越大,需要做的体力工作就越多。
你可以做些什么来避免将来
使您的表架构和索引反射(reflect)数据的真实形状。
varchar
在一张表中,则不太可能需要 nvarchar
中可用的额外字符。换一张 table 。避免对 ID 进行转换的需要,并尽可能使用整数而不是字符。 INCLUDE
TradeReportId 索引中 table3 中需要的所有字段。索引已经帮不上忙的原因是它们可以很容易地确定如何重新排序,但仍然没有物理完成。这是它希望使用惰性假脱机优化的工作,但如果包含数据,它将已经可用,因此无需优化。 关于sql-server - order by 会大大减慢查询速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33948706/
我是一名优秀的程序员,十分优秀!