AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 152530
Accepted
BanksySan
BanksySan
Asked: 2016-10-18 12:50:38 +0800 CST2016-10-18 12:50:38 +0800 CST 2016-10-18 12:50:38 +0800 CST

加载大量测试数据的快速方法

  • 772

我试图用大量虚拟数据填充一个表,以便我可以进行优化等。

我有以下内容:

WHILE @RowCount < 3000000
BEGIN

    SELECT @Random = ROUND(@Upper * RAND(), 0)

    INSERT INTO [dbo].[Test]
               ([Id]
               ,[OtherKey]
               ,[Description])
         VALUES
               (@RowCount
               ,@Random
               ,CAST(@Random AS VARCHAR(max)))

    SET @RowCount = @RowCount + 1
END

但是,这似乎很慢。

有没有更好的方法来自动将半随机行加载到数据库表中?

新脚本

这个似乎很快:

USE [Test]
GO

/****** Object:  Table [dbo].[Test]    Script Date: 17/10/2016 21:22:39 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

USE [Test]
GO

CREATE TABLE [dbo].[Test](
    [Id] [int] NOT NULL,
    [OtherKey] [int] NOT NULL,
    [Description] [varchar](max) NOT NULL,
    [Time] [datetime] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

-- Add sample data

DECLARE @RowCount INT
DECLARE @Random INT
DECLARE @Upper INT

SET @Upper = 1000
SET @RowCount = 0

WHILE @RowCount < 1000000
BEGIN

    SELECT @Random = ROUND(@Upper * RAND(), 0)

    INSERT INTO [dbo].[Test]
               ([Id]
               ,[OtherKey]
               ,[Description]
               ,[Time])
         VALUES
               (@RowCount
               ,@Random
               ,CAST(@Random AS VARCHAR(max))
               ,GETDATE())

    SET @RowCount = @RowCount + 1
END

GO

/****** Object:  Index [IX_ID]    Script Date: 17/10/2016 22:18:48 ******/
CREATE CLUSTERED INDEX [IX_ID] ON [dbo].[Test]
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO



/****** Object:  Index [IX_OtherKey]    Script Date: 17/10/2016 21:22:46 ******/
CREATE NONCLUSTERED INDEX [IX_OtherKey] ON [dbo].[Test]
(
    [OtherKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

如果有人有更快的方法,那么我会很高兴听到它。

sql-server performance
  • 1 1 个回答
  • 3953 Views

1 个回答

  • Voted
  1. Best Answer
    Joe Obbish
    2016-10-18T14:08:24+08:002016-10-18T14:08:24+08:00

    以下是加载大量测试数据的一些指导原则:

    1) 尽可能使用最少的日志记录。

    如果您可以避免将不必要的数据写入事务日志,那太好了,为什么不这样做呢?这将要求您的测试数据库使用简单的恢复模式。您还需要小心遵守允许您获得最少日志记录的规则。如果您需要插入到具有已包含数据跟踪标志 610 的聚集索引的表中,则可以提供帮助。

    2) 避免导致不必要开销的表和列 DDL 选择。

    正如您发现的那样,有时在加载数据之后而不是在加载之前创建聚集索引更有效,尽管它可以根据数据采用任何一种方式。有时创建聚集索引之后可能会更快,因为 SQL Server 可以将数据并行插入到现有堆中(从 SQL Server 2016 开始),并且它可以并行创建聚集索引。这不会是最低限度的记录操作,它需要对表的所有数据进行排序,因此如果您的开发系统不够大,这可能不起作用。

    正如您还发现的那样,一定要在加载数据之后而不是之前创建非聚集索引。

    我相信使用 VARCHAR(MAX) 数据类型有一些开销,所以如果可能的话我会避免这种情况。

    3) 尽可能避免逐行操作。SQL Server 通常使用基于集合的解决方案更有效。

    您的代码中有一些逐行操作。您正在执行 WHILE 循环,一次只处理一行。您还为插入的每一行创建了一个事务。创建和提交事务一定有一些开销,对吧?为什么要为每一行付钱?如果您的系统足够大,您通常可以通过单个查询插入测试数据,特别是如果您能够使用最少的日志记录。

    4) 尽可能使用并行。

    您的代码一次运行一行,无法利用服务器上的多个内核。

    我将为您提供一种解决此类问题的方法,但此查询可能无法完全满足您的需求。

    WITH
    L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
    L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
    L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
    L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
    L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3),
    L5 AS (SELECT 1 AS c FROM L4 A CROSS JOIN L4),
    NUMS AS (SELECT 1 AS NUM FROM L5)   
    SELECT TOP 1000000
      CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS INT) [ID]
    , CAST(t.RAND_VALUE AS INT) [OTHERKEY]
    , CAST(t.RAND_VALUE AS VARCHAR(100)) [DESCRIPTION]
    , CAST(GETDATE() AS DATETIME) [TIME]
    INTO [X_JRO_TEST_RAND_2]
    FROM NUMS CROSS JOIN (SELECT ROUND(1000 * RAND(CHECKSUM(NEWID())), 0) RAND_VALUE) t;
    

    我将使用我在帖子顶部列出的指导原则为您分解查询。

    1) SELECT INTO 创建一个 HEAP 表作为插入的一部分。如果数据库有一个简单的恢复模型,那么这个操作将被最小化记录。我可以通过不将不必要的数据写入事务日志来节省工作。

    2) 表在加载数据之前没有任何索引。我也在使用 VARCHAR(100) 而不是 VARCHAR(MAX)。

    3)为了有效地生成数字,我使用了Itzik Ben-Gan推广(可能创建)的技术。所有的 CTE 都在那里生成 1000000 行。我会查看文章以获取有关该方法如何工作的更多详细信息。为了使 RAND() 为每一行返回不同的值,我使用了此堆栈溢出帖子中记录的技术之一。

    4) 从 SQL Server 2014 开始,查询优化器可以在使用 SELECT INTO 语法时将数据并行插入到堆中。从 SQL Server 2016 开始,即使没有 SELECT INTO 语法,查询优化器也可以将数据并行插入到堆中。在我的测试系统上,查询并行运行。

    在这里的测试系统上,您的代码需要 10:30 来处理一百万行,但上面的查询只需要 23 秒。我只测量了数据加载步骤,并没有打扰索引。值得指出的是,可能有更有效的方法可以以您想要的形式生成数据,而且我的代码中的 TIME 列没有不同的值。

    还值得指出的是,如果您的解决方案运行得足够快以满足您的目的,那太好了,继续保持它。有时没有必要从代码中获得所有最后一点性能,尤其是为了开发目的而在幕后运行的代码。

    • 6

相关问题

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve