如何加快查询执行速度 MySQL

How to speed up query execution MySQL

您必须填写表格 table 1 到 1,000,000:

Table view
CREATE TABLE `test` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , `value` INT UNSIGNED NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;"

我写了一个函数来做这个,但是向table添加数据太慢了,如何提高插入数据的性能?

function InsertData(){

    global $MySQL;
    for($i = 1; $i != 1000000; $i++){
        $MySQL->query("INSERT INTO `name` (`id`, `value`) VALUES ($i, $i);");
    }

    $MySQL->close();
}

如何使用递归 CTE 将逻辑移至数据库?

insert into name (id, value)
with recursive cte as (
    select 1 id
    union all select id + 1 from cte where i < 1000000
)
select id, id from cte

这可能需要通过递归一次生成很多行。另一种方法是只生成 10 行,然后乘以这些行:

insert into name (id, value)
with recursive cte as (
    select 0 id
    union all select id + 1 from cte where i < 9
)
select id, id 
from (
    select 1 + c0.id + c1.id * 10 + c2.id * 100 + c3.id * 1000 + c4.id * 10000 + c5.id * 100000 id
    cte c0
    cross join cte c1
    cross join cte c2
    cross join cte c3
    cross join cte c4
    cross join cte c5
) t

您可以使用 Transactions 以便每数千次插入仅提交一次(或者,如果您勇敢的话,在数百万次查询之后)。这是(勇敢的)例子:

function InsertData(){
   global $MySQL;

   // Start transactions
   $MySQL->query('SET autocommit=0;');
   $MySQL->query('START TRANSACTION;');

   for($i = 1; $i != 1000000; $i++){
      $MySQL->query("INSERT INTO `name` (`id`, `value`) VALUES ($i, $i);");
   }
   // So far, nothing as actually been saved to database
  
   // Commit all inserts.
   $MySQL->query('COMMIT;');
   $MySQL->query('SET autocommit=1;');

   $MySQL->close();
}

如果由于某些 MySQL 限制,这对于单个事务来说太多了,您可以每 10.000 次左右的插入执行一次提交:

function InsertData(){
   global $MySQL;

   // Start transactions
   $MySQL->query('SET autocommit=0;');
   $MySQL->query('START TRANSACTION;');

   for($i = 1; $i != 1000000; $i++){
      $MySQL->query("INSERT INTO `name` (`id`, `value`) VALUES ($i, $i);");
      if($i % 10000 == 0) {
         $MySQL->query('COMMIT;');
         $MySQL->query('START TRANSACTION;');
      }
   }
   // So far, nothing as actually been saved to database
  
   // Commit all inserts.
   $MySQL->query('COMMIT;');
   $MySQL->query('SET autocommit=1;');

   $MySQL->close();
}

注意最终的限制 ->

当然,这是一个实验或 one-shot 脚本。不建议在生产数据库中执行。

试试这个查询:

INSERT INTO `test` (`id`, `value`) 
SELECT @row := @row + 1 AS row, @row 
FROM (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) AS t1,
     (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) AS t2, 
     (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) AS t3, 
     (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) AS t4, 
     (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) AS t5, 
     (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) AS t6, 
     (SELECT @row:=0) AS nums;

这是一种“INSERT INTO...SELECT...”类型的语句,其中 SELECT 语句本身生成了一百万行,其中包含对 (1,1),( 2,2), 等等。这是它的工作原理:

  1. table的t1,t2,t3,t4,t5,t6各10行。将它们交叉连接会生成 10^6 = 1000000 个组合,因此生成的 table 将包含百万行;
  2. 对于这些行中的每一行,我们 SELECT @row 变量两次。不仅如此,我们还将它增加 1;
  3. nums table只是用来在最开始将变量初始化为0;
  4. 生成的 table 被传递给 INSERT 语句,数据存储在 table.

一个看起来更简洁的解决方案是使用更新的递归 CTE MySQL/MariaDB。这是 :

INSERT INTO test (id, value)
WITH RECURSIVE temp AS (
    SELECT 1 AS row
    UNION SELECT row + 1 
    FROM temp
    WHERE row < 1000000
)
SELECT row, row
FROM temp;

根据我的测试,它有点慢。我没有监控内存使用情况。