2

最近,我遇到了一种在 SELECT 查询中对数据进行排序的模式(不确定,可能是反模式)。该模式更像是一种用于排序数据的冗长且非声明性的方式。该模式是将实际表中的相关数据转储到临时表中,然后将 orderby 应用于临时表上的字段。我想,有人这样做的唯一原因是提高性能(我对此表示怀疑)而没有其他好处。

例如,假设有一个用户表。该表可能包含数百万行。我们要检索名字以“G”开头并按名字排序的所有用户。在这种情况下实现 SQL 查询的自然且更具声明性的方式是:

更自然和声明的方式

SELECT * FROM Users
WHERE NAME LIKE 'G%'
ORDER BY Name

详细方式

SELECT * INTO TempTable
FROM Users
WHERE NAME LIKE 'G%'

SELECT * FROM TempTable
ORDER BY Name

在这种情况下,我有几个问题:

  1. 如果名字字段上没有索引,两种方式之间是否会有任何性能差异。如果是的话,哪一个会更好。

  2. 如果名字字段上有索引,两种方式之间是否会有任何性能差异。如果是的话,哪一个会更好。

  3. SQL Server 优化器不应该为这两种方式生成相同的执行计划吗?

  4. 从锁定/阻塞之类的任何其他方面编写详细的方式有什么好处吗?

提前致谢。

4

3 回答 3

1

Reguzlarly:不知道自己在做什么的人的反模式。

有时:好的,因为 SQL Server 有一个无法以其他方式解决的问题——不过,虽然没有见过这个问题。

它使事情变慢,因为它强制 tmpddb 表首先完全填充,否则查询可能会更有效地解析。

上次看到那是3年前的事了。由于不聪明并使用 tempdb 表,我们得到了 3 倍的速度;)

答案:

1:不,显然它仍然需要表扫描。

2:可能 - 取决于数据量,但按索引查找的索引将已按顺序包含数据(因为索引按内容排序)。

3:没有。明显地。查询计划优化是逐语句进行的。通过削减 2 中的执行,查询优化器不能将连接合并到第一条语句中。

4:仅当您遇到查询优化器问题或您可以加入多少表的限制时 - 不是在那种退化的情况下(在技术意义上退化 - 即非常简单)。但是,如果您需要加入许多表,最好采用临时步骤。

于 2012-06-26T13:05:20.853 回答
0

如果您想要通过 on 进行排序的字段没有被索引,您可以将所有内容放入临时表并对其进行索引,然后进行排序,它可能会更快。您必须进行测试才能确定。

于 2012-06-26T13:42:49.467 回答
0

我能想到的第二种方法从来没有任何好处。

这意味着如果数据可用,预购的 SQL Server 将无法利用这一点,并在计划中添加不必要的阻塞运算符和额外的排序。

在数据不可用的情况下,预先订购的 SQL Server 将在内存中或tempdb无论如何在工作表中对其进行排序,并且添加显式#temp表只会增加不必要的额外步骤。

编辑

我想第二种方法可以带来明显好处的一种情况可能是,如果存在ORDER BY导致 SQL Server 选择一个不同的计划,结果证明是次优的。在这种情况下,我将通过改进统计信息或使用提示/查询重写来避免不受欢迎的计划,以不同的方式解决这个问题。

于 2012-06-26T13:31:18.123 回答