SQL";加上;性能和临时表(可能需要“查询提示”来简化)
给出以下示例查询(仅简化示例) 而且SQL";加上;性能和临时表(可能需要“查询提示”来简化),sql,sql-server,tsql,temp-tables,Sql,Sql Server,Tsql,Temp Tables,给出以下示例查询(仅简化示例) 而且 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 tem
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
两者都产生相同的结果,这是一个基于字段数据的列表中的有限值和排名列表
当这些查询变得相当复杂时(更多的表、大量的条件、多个级别的“with”表等),底部查询的执行速度要比顶部查询快得多。有时速度会快20-100倍
问题是……
是否有某种查询提示或其他SQL选项会告诉SQL Server自动执行相同类型的优化,或者有其他格式会涉及更干净的aproach(尽量保持与查询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
编辑:重要的后续信息强>
如果在子查询中添加
TOP 999999999 -- improves speed dramatically
您的查询的行为方式与在以前的查询中使用临时表类似。我发现执行时间几乎以完全相同的方式提高。这比使用临时表简单得多,基本上就是我想要的
然而
TOP 100 PERCENT -- does NOT improve speed
不以相同的方式执行(必须使用静态数字样式TOP 9999999)
说明:
从这两种格式的查询的实际执行计划中我可以看出(原始的一个具有正常的CTE,而每个子查询具有TOP 9999999)
普通查询将所有内容连接在一起,就好像所有表都在一个大规模查询中一样,这是预期的结果。过滤条件几乎应用于计划中的连接点,这意味着要同时计算和连接更多的行
在TOP 99999999版本中,实际执行计划将子查询与主查询明确分开,以便应用TOP语句操作,从而强制创建子查询的内存“位图”,然后将其连接到主查询。这看起来确实是我想要的,事实上它甚至可能更有效,因为具有大量RAM的服务器将能够完全在内存中执行查询,而无需任何磁盘IO。在我的例子中,我们有280 GB的RAM,比实际使用的内存还要多。问题是,在第一个查询中,SQL Server查询优化器能够生成查询计划。在第二个查询中,由于要将值插入到新的临时表中,因此无法生成良好的查询计划。我猜在你看不到的地方正在进行一次全表扫描
在第二个查询中,您可能希望像以前一样将值插入#LargeData临时表,然后在“valuefield”列上创建一个非聚集索引。这可能有助于提高性能。您不仅可以在临时表上使用索引,还可以使用统计信息和提示。我找不到能够使用CTE文档中的统计数据的参考资料,它特别指出您不能使用提示 当您拥有一个大数据集时,即使您不使用索引(很可能是因为它将使用统计数据来制定计划),临时表通常也是最有效的方法。我可能怀疑CTE的实现更像是表变量,而不是临时表 我认为最好的办法是看看执行计划有什么不同,以确定它是否是可以修复的
当您知道temp表的性能更好时,您反对使用它的具体原因是什么?很可能是SQL针对错误的参数值进行了优化 有两种选择
选项(重新编译)
。这样做是有代价的,因为它每次都会重新编译查询,但如果需要不同的计划,这可能是值得的选项(针对@DT=somerepresentavievalue进行优化)
问题是您选择了错误的值从SQL Server查询优化团队的博客中可以看到您可能需要查看执行计划来解决这些问题,但我很好奇,这是
DECLARE@DT int;设置@DT=20110717
实际上是您正在做的事情,或者是一个参数。这很重要,因为CTE可能会由于参数嗅探而执行不同的操作,而临时表似乎不是(以我的经验来看),您可能想看看这个问题,这正是我在服务器管理器中编写测试查询的方式。结果查询不以这种方式包含参数。在我的现实世界SQL中,它背后的实际逻辑可能太令人难以置信,难以理解,我已经查看了一些查询计划,它们往往非常庞大,以至于你真的无法理解瓶颈。在编辑之后,看起来就像是@MartinSmithYes。在许多情况下,我也会在临时表上创建索引,但你对这个例子的理解倒过来了。即使使用非索引的临时表,第二个查询也会执行第一个查询。这个例子可能不是,但在一个更复杂的例子中,它通常对性能有显著的好处(而且似乎没有任何负面影响)。我只倾向于在出现性能问题时使用临时表格式,这使它更具可读性。更简单的原因是,如果已经以另一种方式构建了这种类型的查询,那么就更容易发现它的哪些部分将受益。以单行或小行的形式下降
TOP 100 PERCENT -- does NOT improve speed