我遇到如下奇怪的情况:
我在名为“Table1”的数据库中有一个巨大的表。 然后,我使用以下代码复制完全相同的表。
Select *
into Table2
from Table1
之后, 我发现查询性能差别很大。
Select count (distinct ID)
from Table1
大约需要2分钟才能完成。 (旧表)
同时,
Select count (distinct ID)
from Table2
大约需要10秒才能完成(新表)
顺便说一句,我发现在“select into”之后数据已在newtable中重新排序。 此外,在“选择进入”新表之前,在表1(旧表)中添加了一列 (这是一个表,将col1添加为col2。)
那么,这是怎么发生的?
(注意:问题的原始版本表明新表格速度很慢。这是一个错误。另外,它没有提到表1中的数据操作)
这是塞巴斯蒂安的代码的结果。
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) 底部图像是指“表2”(数据库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代码
的代码(Running stat)的结果 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”语句创建的,我想两者都应该相同,但现在我很困惑。
答案 0 :(得分:3)
好的,既然我们已经解决了旧表是慢表而不是新表,那么所有内容都指向极大量的转发记录是罪魁祸首。
要删除转发的记录,您可以使用此查询:
ALTER TABLE dbo.Table2 REBUILD;
向堆中添加列很可能会导致每一行频繁移动,从而导致转发记录数量非常大。 forwarded_records_count
DMV返回的列sys.dm_db_index_physical_stats
显示了转发的数量 - 几乎是您案例中的所有行。
SELECT * INTO
不会复制转发指针,而是重新组织它。因此,你看到的性能差异。
虽然我们在谈论前锋,但在大多数情况下,在桌面上拥有聚集索引是一个非常好的主意。这避免了这样的问题。
在您的情况下,ID列似乎是群集主键的候选者(如果它是唯一的),但我需要了解更多有关该模型的信息,以便在此处给出推荐。
答案 1 :(得分:1)
另一个尝试:请运行此文章并发布文本以及查询结果。一如既往地确保用实名替换Table1和Table2。在这种情况下,您还需要替换数据库名称。
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO
SELECT COUNT(DISTINCT ID) FROM DB1.dbo.Table1
GO
SELECT COUNT(DISTINCT ID) FROM DB2.dbo.Table2
GO
SELECT COUNT(DISTINCT ID) FROM DB1.dbo.Table1
GO
SELECT COUNT(DISTINCT ID) FROM DB2.dbo.Table2
GO
SELECT COUNT(DISTINCT ID) FROM DB1.dbo.Table1
GO
SELECT COUNT(DISTINCT ID) FROM DB2.dbo.Table2
GO
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
GO
SELECT * FROM sys.dm_db_index_operational_stats(DB_ID('DB1'),OBJECT_ID('DB1.dbo.Table1'),NULL,NULL);
SELECT * FROM sys.dm_db_index_operational_stats(DB_ID('DB2'),OBJECT_ID('DB2.dbo.Table2'),NULL,NULL);
答案 2 :(得分:0)
我认为这是由过时的统计数据引起的。但我们需要更多关于您的环境的信息。你能运行这两个查询并发布结果吗?确保使用两个表的名称而不是提供的两个表。
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();