4

我遇到如下奇怪的情况:

我在名为“Table1”的数据库中有一个巨大的表。然后,我使用以下代码复制完全相同的表。

Select * into Table2 from Table1

之后,我发现查询性能差异很大。

Select count (distinct ID) from Table1 大约需要 2 分钟才能完成。(旧表)

同时, Select count (distinct ID) from Table2 只需大约 10 秒即可完成(新表)

顺便说一句,我发现数据在“选择进入”之后已经在新表中重新排序。此外,在“选择”新表之前,在 Table1(旧表)中添加了一列(即 Alter a table ,将 col1 添加为 col2。)

那么,这是怎么发生的呢?

(注意:问题的原始版本说新表是慢表。这是一个错误。另外,它没有提到 Table1 上的数据操作)


对更多信息请求的回应

这是塞巴斯蒂安代码的结果。

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

上图参考“表1”(数据库1) 下图参考“表2”(数据库2)


好吧,由于 XML 代码太长,这里是遵循哈姆雷特建议的替代打印输出。我使用 SET SHOWPLAN_ALL ON GO 而不是粘贴所有 XML 代码。我希望它有所帮助。

红色代表“表1”计划,黑色代表“表2”。图像中的文字有点小,但是通过增加此页面大小进行放大只会将其放大。

非常感谢!! 图1


的结果SELECT * FROM sys.dm_db_index_physical_stats(db_id(),object_id('YourTable'),NULL,NULL,'Detaile‌​d')

事实上,两张桌子之间存在巨大差异。同样,红色参考“表1”,另一种参考“表2”

这个问题很烦人,它让我发疯,因为我一直在问自己是否应该重建所有表。:( 在此处输入图像描述

实际上它很奇怪,请注意record_count是不同的。但是,当我重新检查时 select COUNT (ID) from id2000,(即计算此表上的总数据行)两个结果都是 2324798,这是 Table_2 的记录计数

此外,“Table2”是由“select * into”语句创建的,我想两者应该是相同的,但现在我很困惑。

在此处输入图像描述 上表是来自 Sebastian 代码的代码(运行状态)的结果


的结果SELECT * FROM sys.dm_db_index_physical_stats(db_id(),object_id('YourTable'),NULL,NULL,'Detaile‌​d')

事实上,两张桌子之间存在巨大差异。同样,红色参考“表1”,另一种参考“表2”

这个问题很烦人,它让我发疯,因为我一直在问自己是否应该重建所有表。:( 在此处输入图像描述

实际上它很奇怪,请注意record_count是不同的。但是,当我重新检查时 select COUNT (ID) from id2000,(即计算此表上的总数据行)两个结果都是 2324798,这是 Table_2 的记录计数

此外,“Table2”是由“select * into”语句创建的,我想两者应该是相同的,但现在我很困惑。

4

3 回答 3

3

好的,既然我们已经整理出旧表是慢表而不是新表,那么一切都表明转发记录的数量非常多是罪魁祸首。

要删除转发的记录,您可以使用此查询:

ALTER TABLE dbo.Table2 REBUILD;

向堆中添加一列很可能会导致每一行频繁移动,从而导致大量转发记录。forwarded_records_countDMV返回的列sys.dm_db_index_physical_stats显示转发的数量 - 在您的情况下几乎所有行。

ASELECT * INTO不复制转发指针,而是重新组织它。因此,您确实看到了性能差异。

当我们谈论转发时,在大多数情况下,在表上拥有一个聚集索引是一个非常好的主意。这样就避免了这样的问题。

在您的情况下,ID 列似乎是集群主键的候选者(如果它是唯一的),但我需要更多地了解该模型才能在此处为您提供建议。

于 2012-12-26T15:31:51.283 回答
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);
于 2012-12-26T12:19:30.360 回答
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();
于 2012-12-25T17:06:53.223 回答