我遇到了如下奇怪的情况:
我在名为“Table1”的数据库中有一个巨大的表。 然后,我使用以下代码复制完全相同的表。
选择*
代入表2
来自表1
之后, 我发现查询性能有显着差异。
选择计数(不同 ID)
来自表1
大约需要 2 分钟才能完成。 (旧表)
同时,
选择计数(不同 ID)
来自表2
只需大约 10 秒即可完成(新表)
顺便说一句,我发现在“select into”之后,newtable 中的数据已重新排序。 此外,在“选择”新表之前,在 Table1(旧表)中添加了一列 (即更改表格,将 col1 添加为 col2。)
那么,这是怎么发生的呢?
<小时/>(NB: The original version of the question stated that the new table was the slow one. This was an error. Also, it didn't mention about the data manipulation on Table1)
对更多信息请求的回复
这是 Sebastian 代码的结果。
SELECT QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + '.' + QUOTENAME(t.name) tbl,
s.name stats_name,
cols.cols,
t.create_date table_date,
STATS_DATE(s.object_id, s.stats_id) AS statistics_date,
s.auto_created,
s.user_created,
s.no_recompute,
s.has_filter,
s.filter_definition
FROM sys.tables t
LEFT OUTER JOIN sys.stats s
ON s.object_id = t.object_id
OUTER APPLY (
SELECT STUFF((SELECT ',' + c.name
FROM sys.stats_columns sc
JOIN sys.columns c
ON sc.column_id = c.column_id
AND sc.object_id = c.object_id
WHERE sc.object_id = s.object_id
AND sc.stats_id = s.stats_id
ORDER BY sc.stats_column_id
FOR XML PATH(''),
TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') cols
) cols
--Update Table Name(s) here:
WHERE t.OBJECT_ID IN ( OBJECT_ID('[Sales].[SpecialOffer]'),
OBJECT_ID('[Sales].[SalesOrderDetail]') );
和
SELECT name,
compatibility_level,
is_auto_close_on,
is_auto_shrink_on,
state_desc,
is_auto_create_stats_on,
is_auto_update_stats_on,
is_auto_update_stats_async_on
FROM sys.databases
WHERE database_id = DB_ID();
实际上,我将新表复制到另一个数据库。 而表名实际上命名为ID2000
上图引用“Table1”(数据库1) 下图引用“Table2”(数据库2)
<小时/>
好吧,由于 XML 代码太长,这里是遵循哈姆雷特建议的替代打印输出。
我用
SET SHOWPLAN_ALL ON GO
而不是粘贴所有 XML 代码。希望对您有所帮助。
红色代表“表1”计划,黑色代表“表2”计划。 图像中的文字有点小,但是通过增加此页面尺寸来放大只会放大它。
非常感谢!!
<小时/>SELECT * FROM sys.dm_db_index_physical_stats(db_id(),object_id('YourTable'),NULL,NULL,'Detailed') 的结果
。
确实,两个表之间存在巨大差异。 同样,红色代表“表1”,红色代表“表2”
这个问题很烦人,它让我发疯,因为我一直问自己是否应该重建所有表。 :(
实际上这很奇怪,请注意 record_count 是不同的。
但是,当我重新检查时
select COUNT (ID) from id2000
,(即计算该表上的总数据行数)
两个结果都是2324798,即Table_2的record_count
此外,“Table2”是由“select * into”语句创建的,我想两者应该是相同的,但现在我很困惑。
上表是 Sebastian 代码(运行统计)的结果
<小时/>SELECT * FROM sys.dm_db_index_physical_stats(db_id(),object_id('YourTable'),NULL,NULL,'Detailed') 的结果
。
确实,两个表之间存在巨大差异。 同样,红色代表“表1”,红色代表“表2”
这个问题很烦人,它让我发疯,因为我一直问自己是否应该重建所有表。 :(
实际上这很奇怪,请注意 record_count 是不同的。
但是,当我重新检查时
select COUNT (ID) from id2000
,(即计算该表上的总数据行数)
两个结果都是2324798,即Table_2的record_count
此外,“Table2”是由“select * into”语句创建的,我想两者应该是相同的,但现在我很困惑。
最佳答案
好吧,既然我们已经弄清楚旧表是慢表而不是新表,一切都表明转发记录量极高是罪魁祸首。
要删除转发的记录,您可以使用以下查询:
ALTER TABLE dbo.Table2 REBUILD;
向堆中添加列很可能会导致每行频繁移动,从而导致大量转发记录。 sys.dm_db_index_physical_stats
DMV 返回的 forwarded_records_count
列显示转发数量 - 几乎您案例中的所有行。
SELECT * INTO
不会复制转发指针,而是对其进行重新组织。因此您确实看到了性能差异。
当我们谈论转发时,在大多数情况下,在表上拥有聚集索引是一个非常好的主意。这样就避免了类似的问题。
在您的情况下,ID 列似乎是聚集主键的候选者(如果它是唯一的),但我需要了解有关该模型的更多信息才能在此处为您提供建议。
关于SQL : Weird query performance after "select into" a new table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14031665/