首页 文章

理解在SQL Server中合并Vs散列连接

提问于
浏览
0

我已经对查询集进行了测试以查看性能 . 我发现没有聚集索引的查询很快,为什么......?

查询如下

从table1中选择A.col1,B.col2,B.col3 A.col1 = B.col1上的内连接table2

表现是

Hash Match( both have No Index or either have no index)

(913271行受影响)表'表B' . 扫描计数5,逻辑读取18681,物理读取193,预读读取18681,lob

逻辑读取0,lob物理读取0,lob预读读取0.表'表B' . 扫描计数5,逻辑读取57798,物理读取4,预读读取57798,lob逻辑读取0,lob

物理读取0,lob预读读取0.表'工作表' . 扫描计数0,逻辑读取0,物理读取0,预读取读取0,lob逻辑读取0,lob物理

读取0,lob预读读取0 .

(1排受影响)

SQL Server执行时间:CPU时间= 3665 ms,已用时间= 9391 ms .

总时间:09秒

enter image description here

Merge Join:(Both have unique non clustered index)

(913271行受影响)表'表B' . 扫描计数1,逻辑读取18723,物理读取6,预读读取18727,lob

逻辑读取0,lob物理读取0,lob预读读取0.表'表B' . 扫描计数1,逻辑读取56811,物理读取21,预读读取56921,lob逻辑读取0,lob

物理读取0,lob预读读取0 .

(1排受影响)

SQL Server执行时间:CPU时间= 1466 ms,已用时间= 14881 ms . SQL Server解析和编译时间:

总时间:14秒

enter image description here

2 回答

  • 0

    两种索引类型的相对性能在很大程度上取决于各种表中值的分布 . 两种索引类型都支持允许它们避免读取新块和/或能够重新使用已经缓存的块的情况,以有利地利用"read-ahead"策略,等等 . 但是,他们执行此操作的实用能力取决于数据以及正在执行的特定操作 .

    您的应用程序设计的一部分应该是务实的检查,以确定一种方法(如果有的话)“在y-o-u-r情况下”明显优于另一种方法 . 但是,实际上并没有“事实上的胜利者 . 其他的”指数类型很久以前就会被抛弃 . )

    “单一,孤立,资源消耗测试”是不够的:您必须考虑所有角度,包括执行各种操作所需的时间(不仅仅是一个),数据量的影响等等等 .

  • 0

    我觉得这里有两个问题 . 要阅读并理解Merge vs Hash连接的内容,请参阅MSDN文档 . 但是我看到的第二个问题是你滥用SQL Server并试图理解查询计划之间的区别 .

    我将回答第二个问题(谷歌“Hash Join”回答第一个问题) . 查询性能取决于用于连接列的数据类型和页面中的项目数 .

    但是!!这里最重要的是你正在倾倒整个表(我看到上面的并行连接图标让我想到了一个糟糕的查询) . 所以SQL Server正试图找到最快的方式来游泳整个事情并抽出数据 . 我的问题---您的应用程序是否真的意味着转储所有数据?或者JOIN或WHERE子句会有更多内容吗?您正在尝试针对非现实查询进行优化 .

    您所看到的是基于数据分布的统计(直方图)生成的不同查询计划 . 出于某种原因,SQL Server“认为”该计划是最好的 . 数据显然存在偏差,SQL Server认为(平均而言)扫描整个表以完成工作(更少的I / O成本)更快 . 如果数据集很小 - 那么SQL Server认为转储数据比处理以下索引更快 . 或者没有可用的索引看起来会有所帮助(在这种情况下---你要转储所有数据 - 所以SQL Server很可能更喜欢Clustered索引,如果存在,在某些情况下最窄的索引,因为I / O将最小的) .

    当索引丢失时(一个堆表) - SQL Server没有任何东西可以继续并转储表并使工作失明 . 尝试在主键上创建聚簇索引 . 虽然 - 在这种特定情况下,它可能无济于事,因为您正在转储所有数据 .

    其他要考虑的事项:“col1”中的值是唯一的(1:1,或1:*)....还是n:n?您需要在创建表时声明这一点(创建唯一索引或主键) . 此信息是SQL Server“学习”有关未来数据的一种方式 . 您所做的一切都是将您的意图传达给SQL Server的方法,以便它可以做正确的事情 .

    现在我将继续定义你的表和索引(仅在需要时 - 从主键开始) - 写一些真实的查询(可能添加一个索引) - 然后查看你的结果 . 否则你就会过早地进行优化 .

    对索引的(一般)规则是:尽可能少地使用尽可能少的列 - 从而最大化使用 . 指数是数据时必须更新的结构被添加或修改到表中 . 所以更多的索引和大量的列将最终减慢你的速度 . 你只想要你想要的东西 - 而不是更多 . 另见 - 3只小熊的故事 .

    SQL Server的另一个规则 - 拥有聚簇索引 . 堆表被认为是“糟糕的” . 是的,有一个堆的论据 - 但恕我直言,这是一个400级的讨论 . 开始 - 声明PK和群集 .

    祝好运 .

相关问题