SQL“ WITH”性能和临时表(可以简化“ Query Hint”)

Dar*_*nMB 5 sql t-sql sql-server temp-tables

给定以下示例查询(仅简化示例)

DECLARE @DT int; SET @DT=20110717; -- yes this is an INT
WITH LargeData AS (
    SELECT * -- This is a MASSIVE table indexed on dt field
    FROM mydata
    WHERE dt=@DT
), Ordered AS (
    SELECT TOP 10 * 
        , ROW_NUMBER() OVER (ORDER BY valuefield DESC) AS Rank_Number
    FROM LargeData
)
SELECT * FROM Ordered
Run Code Online (Sandbox Code Playgroud)

还有...

DECLARE @DT int; SET @DT=20110717;

BEGIN TRY DROP TABLE #LargeData END TRY BEGIN CATCH END CATCH; -- dump any possible table.

SELECT * -- This is a MASSIVE table indexed on dt field
INTO #LargeData -- put smaller results into temp
FROM mydata
WHERE dt=@DT;

WITH Ordered AS (
    SELECT TOP 10 * 
        , ROW_NUMBER() OVER (ORDER BY valuefield DESC) AS Rank_Number
    FROM #LargeData
)
SELECT * FROM Ordered
Run Code Online (Sandbox Code Playgroud)

两者都产生相同的结果,这是基于字段数据的列表中有限的,排序的值列表。

当这些查询变得相当复杂时(许多表,许多条件,“带有”表的多个层次,等等),底部查询的执行速度比顶部查询快得多。有时速度要快20到100倍。

问题是...

是否存在某种查询HINT或其他SQL选项,它们会告诉SQL Server自动执行相同类型的优化,还是存在涉及更简洁方法的其他格式(尝试使该格式尽可能与查询1保持一致) )?

请注意,在本例中,“排名”或辅助查询只是起毛作用,实际上执行的实际操作并不重要。

这是我所希望的(或类似,但我希望这个主意很明确)。请记住,以下查询实际上并不起作用。

DECLARE @DT int; SET @DT=20110717;
WITH LargeData AS (
    SELECT * -- This is a MASSIVE table indexed on dt field
    FROM mydata
    WHERE dt=@DT
    **OPTION (USE_TEMP_OR_HARDENED_OR_SOMETHING) -- EXAMPLE ONLY**
), Ordered AS (
    SELECT TOP 10 * 
        , ROW_NUMBER() OVER (ORDER BY valuefield DESC) AS Rank_Number
    FROM LargeData
)
SELECT * FROM Ordered
Run Code Online (Sandbox Code Playgroud)

编辑:重要的后续信息!

如果在子查询中添加

 TOP 999999999      -- improves speed dramatically
Run Code Online (Sandbox Code Playgroud)

您的查询的行为类似于在上一个查询中使用临时表的方式。我发现执行时间几乎完全相同。然后使用临时表的那是最简单的,基本上就是我想要的。

然而

 TOP 100 PERCENT    -- does NOT improve speed
Run Code Online (Sandbox Code Playgroud)

不能以相同的方式执行(必须使用静态数字样式TOP 999999999)

说明:

从我可以从两种格式的查询的实际执行计划中得知(原始格式为具有正常CTE的查询,以及每个子查询具有TOP 99999999的查询)

普通查询将所有表连接在一起,就好像所有表都在一个大型查询中一样,这是所期望的。过滤条件几乎应用于计划中的连接点,这意味着正在评估更多的行并将它们一次连接在一起。

在具有TOP 999999999的版本中,实际的执行计划明确地将子查询与主查询分开,以便应用TOP语句操作,从而强制创建子查询的内存“位图”,然后将其连接到主查询。查询。这似乎确实可以实现我想要的功能,实际上,它甚至可能更加高效,因为具有大量RAM的服务器将能够完全在MEMORY中执行查询执行,而无需任何磁盘IO。在我的情况下,我们有280 GB的RAM,因此可以真正使用更多的RAM。

HLG*_*GEM 4

您不仅可以在临时表上使用索引,而且还允许使用统计信息和提示。我在 CTE 文档中找不到关于能够使用统计数据的参考资料,并且明确指出您不能使用提示。

当您有一个大型数据集时,即使您不使用索引(可能是因为它将使用统计信息来制定计划),在临时表和表变量之间进行选择,临时表通常也是最高效的方法,我可能会怀疑 CTE 的实现更像是表变量而不是临时表。

我认为最好的办法是看看执行计划有何不同,以确定它是否可以修复。

当您知道临时表性能更好时,您到底反对使用它吗?