How is a TSQL Join implemented internally when there is a many-to-single relationship?
如果这篇文章在其他地方发表,我很抱歉;有那么多关于加入副本的问题,我找不到答案。注意,这个问题并不是问如何删除结果中的重复行。
采用以下方案,其中两个表使用文本匹配进行联接,但其中一个表包含大量重复项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | CREATE TABLE #test (ID int PRIMARY KEY IDENTITY(1,1), textval nvarchar(250)); INSERT INTO #test (textval) VALUES (N'Luke'),(N'Han'),(N'Vader'); DECLARE @tmp TABLE (textval nvarchar(250)); INSERT INTO @tmp VALUES (N'Luke'),(N'Luke'),(N'Luke'),(N'Luke'),(N'Luke'),(N'Jabba'); -- Query 1 SELECT tmp.textval, t.ID FROM @tmp tmp LEFT JOIN #test t ON tmp.textval = t.textval; DROP TABLE #test; |
我在这里得到想要的输出…
…但是,这是执行此查询的有效方法吗?具体地说,我想知道TSQL是否会在表变量中的"luke"的每个实例上创建一个join,或者在内部删除重复项,因此只查找一次"luke",而不是五次查找五个实例?
我试着看一下统计数据和执行计划,但不知道什么数字表示正在发生的事情。
更新根据Remus的回答,这里是上述查询的执行计划,显示零重绕/重绕。
以下是回放/重放图的屏幕抓图:
您正在询问连接是如何实现的。主要有三种策略:
- 嵌套循环
- 搞砸
- 合并
它们都不会"消除"重复项,因为这样做在语义上是错误的。但是,hash和merge join都只能"访问"
SQL没有自动删除重复项的方法
如果要删除所有列中的重复项,那么只需使用
1 2 3 4 5 6 | SELECT DISTINCT tmp.textval, t.ID FROM @tmp tmp LEFT JOIN #test t ON tmp.textval = t.textval; |
或者,如果需要根据某些特定列删除重复项,则可以尝试使用
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ;WITH CTE AS ( SELECT RN = ROW_NUMBER() OVER(PARTITION BY tmp.textval ORDER BY t.ID), tmp.textval, t.ID FROM @tmp tmp LEFT JOIN #test t ON tmp.textval = t.textval; ) SELECT * FROM CTE WHERE RN = 1 |
但是,如果使用