SQL TOP 5000比正常查询更快,结果行少于5000?

前端之家收集整理的这篇文章主要介绍了SQL TOP 5000比正常查询更快,结果行少于5000?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我注意到一些奇怪的行为:

运行此查询

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)

在2秒内结果为3447行.

运行这一个:

SELECT t1.f1,t1.f3 
FROM t1
JOIN t2 on t1.f1 = t2.f1
WHERE t2.f1 IS NOT NULL AND (t1.f5 != t2.f3)

永远跑,直到我停止(至少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]

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,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

执行计划:

顶部:

没有顶部:

看这个,我必须得出结论,排序(为什么这样做)导致延迟…你会同意吗?

编辑2:根据要求,执行计划与循环选项没有顶部:

解决方法

问题是,您的两个表[t1]和[t2]与JOIN列f1完全不同(并且很大程度上是不兼容的)数据类型.

这使得查询优化器无法生成在两个500,000行表之间匹配多少行的准确估计.似乎使用默认的“猜测”,在这种情况下,实际数字的总体估计值(3477).因此,当您不使用TOP时,它认为排序,然后合并行(O(NLogN))比嵌套循环(O(N ^ 2))更有效,因为它是没有意识到(合并)JOIN实际上会消除几乎所有的行.

当您拥有TOP 5000时,它意识到嵌套循环更好,因为它将被切断不超过5000(远小于500k ^ 2,甚至小于500k * Log(500k)).但与嵌套循环不同,“合并排序”不能逐步完成,因此必须先对排序进行排序.所以在5000以下的输出将不会拯救你,所以嵌套循环显然是更好的选择(即使是坏的JOIN估计).

这里的根本问题是列T2.f1是一个NCHAR(10),对于看起来像它应该包含一个整数的东西来说,这是一个非常糟糕的选择.最佳的解决方案是将该列的数据类型更改为INT.

如果由于某种原因您不能这样做,那么根据您的sql Server版本,您可以通过添加计算INT转换值[f1]的持久计算列来结束运行,然后在该值上引用兼容索引.这将允许索引和统计信息再次工作,这样的查询.

作为最后的手段,您还可以使用查询提示.我通常不推荐他们,因为他们往往是后来发生问题的停滞解决方案.但是,如果您觉得这是您唯一的选择,则将OPTION(FAST 1000)添加到您的查询结尾可能会起作用.

原文链接:https://www.f2er.com/mssql/81085.html

猜你在找的MsSQL相关文章