Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用SELECT TOP x的SQL性能差异巨大,即使x比所选行高得多_Sql_Sql Server_Performance_Tsql_User Defined Functions - Fatal编程技术网

使用SELECT TOP x的SQL性能差异巨大,即使x比所选行高得多

使用SELECT TOP x的SQL性能差异巨大,即使x比所选行高得多,sql,sql-server,performance,tsql,user-defined-functions,Sql,Sql Server,Performance,Tsql,User Defined Functions,我从一个表值函数中选择了一些行,但通过将SELECT TOP放在查询中发现了无法解释的巨大性能差异 SELECT col1, col2, col3 etc FROM dbo.some_table_function WHERE col1 = @parameter --ORDER BY col1 需要5到6分钟才能完成 然而 SELECT TOP 6000 col1, col2, col3 etc FROM dbo.some_table_function WHERE

我从一个表值函数中选择了一些行,但通过将SELECT TOP放在查询中发现了无法解释的巨大性能差异

SELECT   col1, col2, col3 etc
FROM     dbo.some_table_function
WHERE    col1 = @parameter
--ORDER BY col1
需要5到6分钟才能完成

然而

SELECT   TOP 6000 col1, col2, col3 etc
FROM     dbo.some_table_function
WHERE    col1 = @parameter
--ORDER BY col1
大约在4或5秒钟内完成

如果返回的数据集很大,这不会让我感到惊讶,但是特定的查询返回了200000行中的5000行

因此,在这两种情况下,整个表都会被处理,因为SQL Server将继续搜索6000行,而这是它永远也找不到的。那么为什么会有如此巨大的差异呢?这是否与SQL Server在预期结果集大小(前6000名)时分配空间的方式有关,从而使其要求较低,更容易在内存中分配? 还有其他人目睹过这样的事情吗


感谢

表值函数可以具有非线性执行时间

让我们考虑这个查询的函数等价:

SELECT  (
        SELECT  SUM(mi.value)
        FROM    mytable mi
        WHERE   mi.id <= mo.id
        )
FROM    mytable mo
ORDER BY
        mo.value
这些查询:

SELECT  *
FROM    fn_test()
WHERE   name = @name

SELECT  TOP 1000 *
FROM    fn_test()
WHERE   name = @name

产生不同的执行计划(第一个使用聚集扫描,第二个使用带有
TOP
的索引查找)

如果col1有索引,则处理整个表不一定是正确的

SQL优化将选择是否使用索引。也许你的“TOP”迫使它使用索引

如果您使用的是MSSQL查询分析器(我不记得名称),请按Ctrl-K。这将显示查询的执行计划,而不是执行计划。我相信,将鼠标悬停在图标上会显示IO/CPU的使用情况

我打赌其中一个正在使用索引搜索,而另一个没有

如果您有一个通用客户端: 将SHOWPLAN_设置为全部打开; 去 选择。。。; 去


有关详细信息,请参阅。

您可能在这里遇到了缓存这样简单的问题-可能(出于任何原因)缓存了“TOP”查询?使用另一个没有的索引

在任何情况下,消除好奇心的最好方法是检查两个查询的完整执行计划。您可以在SQL管理控制台中正确地执行此操作,它将准确地告诉您正在完成哪些操作以及每个操作预计需要多长时间


所有SQL实现都有其独特的方式——SQL Server也不例外。这种“Whaaaaaaa?!”的时刻很常见

您的TOP没有ORDER BY,因此它与先设置ROWCOUNT 6000完全相同。ORDER BY需要首先计算所有行,这将花费更长的时间

如果
dbo.some_table_function
是一个内联表值udf,那么它只是一个展开的宏,因此它返回前面提到的6000行,没有特定的顺序

如果udf是多值的,那么它是一个黑匣子,在过滤之前总是会拉入完整的数据集。我认为这不会发生


没有直接关系,但我认为卡斯努斯的建议似乎很有道理。通过添加TOP 6000,您隐式地向优化器提示将返回200000行中相当小的子集。然后,优化器使用索引查找而不是聚集索引扫描或表扫描


另一种可能的解释可能是缓存,正如吉姆·戴维斯所说。这很容易通过再次运行查询来排除。首先尝试运行TOP 6000的表。

我也遇到了同样的问题,一个简单的查询连接五个表,返回1000行,需要两分钟才能完成。当我加上“TOP10000”时,它不到一秒钟就完成了。事实证明,其中一个表上的聚集索引是严重碎片化的


重建索引后,查询现在在不到一秒钟的时间内完成。

“在这种情况下可能不会。我的查询的要点是,无论是否使用TOP子句,都会返回相同的行(TOP6000大于结果集)。因此,这与这些行本身的计算无关。
@Arj
:您可以发布您的函数定义吗?@Quassnoi:内联TVF只是一个宏。是的-我正在查看计划。虽然我已经更改了发布的查询。实际上,它是在做SELECT*。我看不出使用TOP将如何提示索引使用?SQL优化器将决定是否使用索引。我做过where子句导致“临界点”的查询,优化器决定进行完整表扫描而不是使用索引。您看过查询计划了吗?有什么不同吗?只是好奇,如果你说选择100%的话,性能会发生什么变化?我猜你有一些统计数据会把查询优化器从kelter中抛出去。例如,如果优化器认为表中的行很少,那么它可能会决定使用表扫描而不是索引查找。我不知道为什么这不会影响顶层查询,但请检查执行计划。这些将向您展示服务器的功能,这将解释为什么服务器运行缓慢。它还将显示估计行数和实际行数。如果某些估计值相差很远,请更新统计信息并重试。:)这只是一个粗略的猜测,但top 6000告诉优化器“为6k记录保存一些内存”,而如果没有这一点,它的错误猜测将只是一些结果,使引擎在运行时重新分配内存。我发现在某些情况下,错误的内存猜测是在ram上运行所有东西和尝试使用TempDB(磁盘)之间的区别
SELECT  *
FROM    fn_test()
WHERE   name = @name

SELECT  TOP 1000 *
FROM    fn_test()
WHERE   name = @name