【问题标题】:Fill database tables with a large amount of test data用大量测试数据填充数据库表
【发布时间】:2011-04-15 13:00:46
【问题描述】:

我需要加载一个包含大量测试数据的表。这将用于测试性能和扩展。

如何轻松地为我的数据库表创建 100,000 行随机/垃圾数据?

【问题讨论】:

  • 您是否已经有了测试数据,还是必须生成它?
  • 你的表结构是什么?以及使用什么语言?
  • 不,我没有任何测试数据,它正在生成它,我正在寻找解决方案。
  • 我有 4 个要加入的表,每个表都有大约一百万条记录,我需要测试我的查询性能,我现在必须用测试数据填充这些表。

标签: mysql database


【解决方案1】:

这是对@michalzuber 答案的更高效的修改。唯一的区别是删除WHERE id = 1,以便每次运行时插入都可以累积。

产生的记录数量为n^2;

所以对于 10 次迭代,10^2 = 1024 条记录 对于 20 次迭代,20^2 = 1048576 条记录等等。

DELIMITER $$
CREATE PROCEDURE insert_test_data()
BEGIN
  DECLARE i INT DEFAULT 1;

  WHILE i <= 10 DO
    INSERT INTO `table` (`user_id`, `page_id`, `name`, `description`, `created`)
    SELECT `user_id`, `page_id`, `name`, `description`, `created`
    FROM `table`;
    SET i = i + 1;
  END WHILE;
END$$
DELIMITER ;
CALL insert_test_data();
DROP PROCEDURE insert_test_data;

【讨论】:

    【解决方案2】:
    create table mydata as select * from information_schema.columns;
    insert into mydata select * from mydata;
    -- repeating the insert 11 times will give you at least 6 mln rows in the table.
    

    如果这不合适,我非常抱歉,但我想对这段代码提供一些解释,因为我知道足以解释它,如果你只了解它的作用,上面的答案是如何相当有用的。

    第一行创建一个名为mydata的表,并从information_schema生成列的布局,其中存储了有关您的MYSQL服务器的信息,在这种情况下,它是从information_schema.columns提取的,它允许正在创建的表包含创建表所需的所有列信息,但您将自动需要所有列,非常方便。

    第二行以Insert 语句开始,该语句现在将指向名为mydata 的新表并将Information_schema 数据插入表中。最后一行只是一个注释,建议您运行脚本几次,以生成更多数据。

    最后总结一下,在我的测试中,该脚本的一次执行生成了 6,956 行数据。如果您需要一种快速的方法来生成一些记录,这不是一个坏方法。但是,对于更高级的测试,您可能希望ALTER 表包含一个自动递增的主键,以便您拥有唯一索引,因为没有主键的数据库是一个可悲的数据库。由于可能存在重复条目,因此它也往往会产生不可预测的结果。话虽如此,我想对这段代码提供一些见解,因为我发现它很有用,我认为其他人也可以,只要他们花时间解释它在做什么。大多数人不喜欢执行他们不知道要做什么的代码,即使来自受信任的来源,所以希望其他人能像我一样发现这很有用。我不是将此作为“答案”,而是作为另一个信息来源,以帮助为上述答案提供一些后勤支持。

    【讨论】:

    • 请不要只发布代码作为答案,还要说明您的代码的作用以及它如何解决问题的问题。带有解释的答案通常质量更高,更有可能吸引投票
    【解决方案3】:

    我真的很喜欢 Percona 的 mysql_random_data_loader 实用程序,您可以在here找到更多详细信息。

    mysql_random_data_loader 是一个连接到 mysql 数据库并用随机数据填充指定表的实用程序。如果表中存在外键,它们也将被正确填充。

    这个实用程序有一个很酷的功能,可以限制数据生成的速度。

    例如要生成30000条记录,在sakila.film_actor表中以每秒500条记录的速度,需要如下命令

    mysql_random_data_load sakila film_actor 30000 --host=127.0.0.1 --port=3306 --user=my_user --password=my_password --qps=500 --bulk-size=1
    

    我已成功使用此工具在测试环境中模拟工作负载,方法是在多个线程上以不同速度针对不同表运行此实用程序。

    【讨论】:

      【解决方案4】:

      试试filldb

      您可以发布您的架构或使用现有架构并生成虚拟数据并从该站点导出并导入您的数据库。

      【讨论】:

        【解决方案5】:

        这是纯数学和 sql 的解决方案:

        create table t1(x int primary key auto_increment);
        insert into t1 () values (),(),();
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 1265 rows affected (0.01 sec)
        Records: 1265  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 2530 rows affected (0.02 sec)
        Records: 2530  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 5060 rows affected (0.03 sec)
        Records: 5060  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 10120 rows affected (0.05 sec)
        Records: 10120  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 20240 rows affected (0.12 sec)
        Records: 20240  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 40480 rows affected (0.17 sec)
        Records: 40480  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 80960 rows affected (0.31 sec)
        Records: 80960  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 161920 rows affected (0.57 sec)
        Records: 161920  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 323840 rows affected (1.13 sec)
        Records: 323840  Duplicates: 0  Warnings: 0
        
        mysql> insert into t1 (x) select x + (select count(*) from t1) from t1;
        Query OK, 647680 rows affected (2.33 sec)
        Records: 647680  Duplicates: 0  Warnings: 0
        

        【讨论】:

        • 您的表格是否只有一列?我喜欢仅复制现有行的概念,但您的查询可能需要稍微调整以使用其他列。您还应该能够插入 NULL 以覆盖 AUTO_INCREMENT 列。
        • 我不喜欢重复行 - 在查询测试时 - 用例可能会导致您在预期结果中看不到查询失败的位置..
        【解决方案6】:

        对于多行克隆(数据复制),您可以使用

        DELIMITER $$
        CREATE PROCEDURE insert_test_data()
        BEGIN
          DECLARE i INT DEFAULT 1;
        
          WHILE i < 100000 DO
            INSERT INTO `table` (`user_id`, `page_id`, `name`, `description`, `created`)
            SELECT `user_id`, `page_id`, `name`, `description`, `created`
            FROM `table`
            WHERE id = 1;
            SET i = i + 1;
          END WHILE;
        END$$
        DELIMITER ;
        CALL insert_test_data();
        DROP PROCEDURE insert_test_data;
        

        【讨论】:

          【解决方案7】:

          您也可以使用stored procedure。以下表为例:

          CREATE TABLE your_table (id int NOT NULL PRIMARY KEY AUTO_INCREMENT, val int);
          

          然后你可以像这样添加一个存储过程:

          DELIMITER $$
          CREATE PROCEDURE prepare_data()
          BEGIN
            DECLARE i INT DEFAULT 100;
          
            WHILE i < 100000 DO
              INSERT INTO your_table (val) VALUES (i);
              SET i = i + 1;
            END WHILE;
          END$$
          DELIMITER ;
          

          当您调用它时,您将拥有 10 万条记录:

          CALL prepare_data();
          

          【讨论】:

          • 你确定它适用于 MySQL 吗?我从未在 MySQL 查询中见过 WHILE
          • 它很好,但我们需要一些平均完整的数据和更多的数据列。
          • @fritzmg 那是因为 i 的初始值设置为 100。
          • 我已经尝试了 200 万行,这需要很长时间,因为它一次提交一行。有一种方法可以并行地做很多事情会很好。我正在考虑以编程方式生成查询字符串可能会改善问题,具体取决于瓶颈所在。话又说回来,它可能只是在生成查询字符串时陷入困境。
          • 如果你忘记增加 i... 这就是我所做的。
          【解决方案8】:

          如果您想对数据进行更多控制,请尝试以下方法(在 PHP 中):

          <?php
          $conn = mysql_connect(...);
          $num = 100000;
          
          $sql = 'INSERT INTO `table` (`col1`, `col2`, ...) VALUES ';
          for ($i = 0; $i < $num; $i++) {
            mysql_query($sql . generate_test_values($i));
          }
          ?>
          

          其中函数 generate_test_values 将返回格式为“('val1', 'val2', ...)”的字符串。如果这需要很长时间,您可以将它们批处理,这样您就不会进行太多的数据库调用,例如:

          for ($i = 0; $i < $num; $i += 10) {
            $values = array();
            for ($j = 0; $j < 10; $j++) {
              $values[] = generate_test_data($i + $j);
            }
            mysql_query($sql . join(", ", $values));
          }
          

          只会运行 10000 个查询,每个查询增加 10 行。

          【讨论】:

          • 稍微延迟循环;避免 MySQL 服务器消失 - 错误,如果你得到它们。
          • 请注意,这个答案已经很老了。 mysql_connect() 已弃用,在 PHP 7 中不再可用。
          猜你喜欢
          • 2010-10-10
          • 2020-03-04
          • 2011-02-08
          • 1970-01-01
          • 1970-01-01
          • 2010-12-23
          • 1970-01-01
          • 2019-03-22
          • 2016-01-17
          相关资源
          最近更新 更多