Der*_*rts 14 sql t-sql sql-server
我注意到一些奇怪的行为:
运行此查询:
SELECT TOP 5000 t1.f1,t1.f2,t1.f3
FROM t1
JOIN t2 on t1.f1 = t2.f1
WHERE t2.f1 IS NOT NULL AND (t1.f5 != t2.f3)
Run Code Online (Sandbox Code Playgroud)
结果在2秒内3447行.
运行这个:
SELECT t1.f1,t1.f2,t1.f3
FROM t1
JOIN t2 on t1.f1 = t2.f1
WHERE t2.f1 IS NOT NULL AND (t1.f5 != t2.f3)
Run Code Online (Sandbox Code Playgroud)
永远运行直到我停止它(至少120分钟!!).
表t1并t2保存约500k记录.
我总是认为TOP如果总行数低于该数字,则该声明无关紧要,但是,似乎存在非常显着的差异.这是正常的(如果是这样,为什么)或者这只是一个侥幸?
编辑:
按照要求:
T1:
CREATE TABLE [dbo].[t1](
[f1] [int] NOT NULL,
[f2] [varchar](10) NULL,
[f3] [varchar](4) NULL,
[f4] [int] NOT NULL,
[f5] [varchar](max) NULL,
CONSTRAINT [PK_t1] PRIMARY KEY CLUSTERED
(
[f1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
F2:
CREATE TABLE [dbo].[t2](
[f1] [nchar](10) NOT NULL,
[f2] [nchar](10) NOT NULL,
[f3] [varchar](max) NOT NULL,
[f4] [nchar](10) NULL,
[f5] [date] NULL,
[f6] [date] NULL,
[f7] [nchar](1) NULL,
CONSTRAINT [PK_t2] PRIMARY KEY CLUSTERED
(
[f1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
执行计划:
顶部:

没有顶部:

看着这个,我不得不得出结论sorting(为什么这样做?)导致延迟...你同意吗?
Edit2:根据要求,带有循环选项的执行计划没有顶部:

RBa*_*ung 13
问题是你的两个表[t1]和[t2]对于JOIN列有完全不同的(并且很大程度上不兼容)数据类型f1.
这使得查询优化器无法准确估计这两个500,000行表之间要匹配的行数.它似乎使用默认的"猜测",在这种情况下是实际数字的总估计过高(3477).因此,当你不使用TOP时,它认为排序然后合并行(O(NLogN))比执行嵌套循环(O(N ^ 2))更有效,因为它确实如此.没有意识到(合并)JOIN实际上会消除几乎所有的行.
当你打开TOP 5000时,它意识到嵌套循环更好,因为它将被切断不超过5000(远小于500k ^ 2,甚至小于500k*Log(500k)).但与嵌套循环不同,Merge-Sort不能以递增方式完成,它必须首先包含Sort的所有行.因此,将输出切断为5000,根本不会为您节省太多,因此使嵌套循环显然是更好的选择(即使JOIN估计错误).
这里的根本问题是列T2.f1是一个NCHAR(10),对于看起来应该包含整数的东西来说,这是一个非常糟糕的选择.最好的解决方案是将该列的数据类型更改为INT.
如果由于某种原因你不能这样做,那么根据你的SQL Server版本,你可以通过添加一个持久的计算列来计算INT转换后的值[f1],然后在其上抛出一个兼容的索引来结束运行.这将允许索引和统计信息再次用于此类查询.
作为最后的手段,您还可以使用查询提示.我通常不推荐它们,因为它们往往是后来导致问题的权宜之计解决方案.但是,如果您认为这是您唯一的选择,那么添加OPTION (FAST 1000)到查询结尾可能会有效.
| 归档时间: |
|
| 查看次数: |
3210 次 |
| 最近记录: |