【问题标题】:SQL insert slow on 1 million rowsSQL 在 100 万行上插入速度很慢
【发布时间】:2012-03-23 10:00:44
【问题描述】:

WITH TOP 100000 (100k) 这个查询在大约 3 秒内完成

WITH TOP 1000000 (1mil) 这个查询大约需要 2 分钟完成

SELECT TOP 1000000
    db_id = IDENTITY(int, 1, 1), *
INTO dbo.tablename
FROM dbname.dbo.tablename

实际执行计划总是:

clustered index scan 4% cost
top
top
compute scalar
insert (96% cost)
select into

该表有 130 万行,第一列有一个 int 主键

我可以以某种方式加快速度吗?我正在使用 SQL Server 2008 R2。

【问题讨论】:

  • 您确定 SQL Server 不只是忙于扩展 .mdf 或 .ldf 吗?
  • 嗯,那么为什么(例如)从 .bak 文件中恢复千兆字节大小的备份比这要快于磁盘空间分配?
  • 因为如果您将自动扩展设置为百分比而不是固定数量,它将不断忙于分配更多空间。恢复(通过现有)数据库时,所需的大小是已知的,可以一次性分配。
  • 简而言之:只需将 .mdf 和 .ldf 设置为合理的大尺寸,然后再次尝试插入测试。
  • 不工作 :( 插入仍然很慢。这样做了:CREATE DATABASE $(db) $(collat​​ion) ALTER DATABASE $(db) SET RECOVERY SIMPLE ALTER DATABASE $(db) MODIFY FILE (NAME = $ (db), SIZE = 3000MB, MAXSIZE = 8TB); ALTER DATABASE $(db) MODIFY FILE (NAME = $(db)_log, SIZE = 3000MB, MAXSIZE = 2TB);

标签: performance tsql insert sql-server-2008-r2


【解决方案1】:

结果显示,100,000 条记录需要 159 毫秒,1,000,000 条记录需要 1,435 毫秒。在 Raid 1 操作系统上,Raid 1 数据、Raid 1 日志、Raid 1 TempDb 所有单独的驱动器。我们的开发环境。

结果显示,100,000 条记录需要 113 毫秒,1,000,000 条记录需要 996 毫秒。在我的带有单个 SSD(三星 840 250GB)的笔记本电脑上。 SSD 的摇滚!!!

结果显示,100,000 条记录需要 188 毫秒,1,000,000 条记录需要 1,880 毫秒。在 Raid 1 操作系统上,Raid 10 数据、Raid 10 日志、Raid 1 TempDb 在生产负载下所有单独的驱动器。

【讨论】:

    【解决方案2】:

    这是一个完整的脚本,显示 100 万所需的时间不到 100,000 的十倍。您的情况可能略有不同,但这表明基本面不是问题。

    结果显示,100,000 条记录需要 146 毫秒,1,000,000 条记录需要 1,315 毫秒。

    这些结果来自我的桌面。如果其他人可以运行脚本并发布他们的结果,那将非常有用。

    罗伯

    USE master;
    GO
    -- Drop database SourceDB
    IF EXISTS (SELECT * FROM sys.databases WHERE name = 'SourceDB') ALTER DATABASE SourceDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    IF EXISTS (SELECT * FROM sys.databases WHERE name = 'SourceDB') DROP DATABASE  SourceDB;
    GO
    -- Create database SourceDB
    CREATE DATABASE SourceDB; 
    ALTER DATABASE SourceDB SET RECOVERY SIMPLE;
    GO
    USE SourceDB;
    GO
    -- Create table SourceDB.dbo.SourceTable
    CREATE TABLE dbo.SourceTable (
        ColID int PRIMARY KEY
    );
    GO
    -- Populate table SourceDB.dbo.SourceTable
    DECLARE @i int = 0;
    WHILE @i < 1300000
    BEGIN
        SET @i += 1;
        INSERT INTO dbo.SourceTable (ColID) VALUES (@i);
    END;
    GO
    -- Drop database Test1
    IF EXISTS (SELECT * FROM sys.databases WHERE name = 'Test1') ALTER DATABASE Test1 SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    IF EXISTS (SELECT * FROM sys.databases WHERE name = 'Test1') DROP DATABASE  Test1;
    GO
    -- Create database Test1
    CREATE DATABASE Test1;
    ALTER DATABASE Test1 SET RECOVERY SIMPLE;
    ALTER DATABASE Test1 MODIFY FILE (NAME = Test1, SIZE = 3000MB, MAXSIZE = 8TB);
    ALTER DATABASE Test1 MODIFY FILE (NAME = Test1_log, SIZE = 3000MB, MAXSIZE = 2TB);
    GO
    USE Test1;
    GO
    IF EXISTS (SELECT * FROM sys.tables WHERE [OBJECT_ID] = OBJECT_ID('dbo.DestinationTable1')) DROP TABLE dbo.DestinationTable1;
    IF EXISTS (SELECT * FROM sys.tables WHERE [OBJECT_ID] = OBJECT_ID('dbo.DestinationTable2')) DROP TABLE dbo.DestinationTable2;
    GO
    DECLARE @n  int       = 100000;
    DECLARE @t1 datetime2 = SYSDATETIME();
    SELECT TOP (@n) db_id = IDENTITY(int, 1, 1), *
    INTO dbo.DestinationTable1
    FROM SourceDB.dbo.SourceTable;
    SELECT DATEDIFF(ms, @t1, SYSDATETIME()) AS ElapsedMs;
    GO
    DECLARE @n  int       = 1000000;
    DECLARE @t1 datetime2 = SYSDATETIME();
    SELECT TOP (@n) db_id = IDENTITY(int, 1, 1), *
    INTO dbo.DestinationTable2
    FROM SourceDB.dbo.SourceTable;
    SELECT DATEDIFF(ms, @t1, SYSDATETIME()) AS ElapsedMs;
    GO
    

    【讨论】:

      猜你喜欢
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 2015-09-21
      相关资源
      最近更新 更多