简体   繁体   English

如何在大型表中以最有效的方式使用SQL

[英]How to use SQL in the most efficient way with very big tables

I have a table purchase something like ( id , buyer_id , seller_id , amount ) with 20-30 millions of records Also i have a table with the same structure purchase_archive and table users_balance ( id , user_id , balance ) 我有一个表, purchase类似的信息( idbuyer_idseller_idamount )20-30百万的记录此外,我有相同结构的表purchase_archive和表users_balanceiduser_idbalance

I should write a script that: 我应该写一个脚本:

  1. Moves records from purchase to purchase_archive table 将记录从purchase移动到purchase_archive
  2. For each moved row users_balance should be updated (user balance should be decreased for amount if he is a buyer, and increased for the same amount if he is a seller) 对于每个移动的行,应该更新users_balance (如果他是买方,则应减少用户余额的amount如果他是卖方,则应增加相同金额的用户的余额)

What is the best way to solve this task? 解决此任务的最佳方法是什么? (PHP + Mysql PDO) (PHP + Mysql PDO)

My assumption is: 我的假设是:

  1. Set table engine to InnoDB 将表引擎设置为InnoDB
  2. SELECT batch of 1000 rows from first table 从第一个表中选择一批1000行
  3. Begin transaction (thats the reason for the InnoDB) 开始交易(这就是InnoDB的原因)
  4. For each row 每行

    4.1 Store id in array ($temp) 4.1在数组中存储ID($ temp)

    4.2 Update balance with query like 4.2用查询更新余额

     SELECT `amount` FROM `purchase` WHERE `id` = :tid LIMIT 1 INTO @amount; UPDATE `users_balance` SET `balance` = CASE WHEN `user_id` = :seller_id THEN `balance` + @amount WHEN `user_id` = :buyer_id THEN `balance` - @amount END WHERE `user_id` IN (:buyer_id, :seller_id); 
  5. Move rows into archive with the query like that: 使用以下查询将行移动到存档中:

      INSERT INTO `purchase_archive` SELECT * FROM `purchase` WHERE `id` IN (".$temp."); DELETE QUICK FROM `transactions` WHERE `id` IN (".$temp."); 
  6. End transaction 结束交易

And repeat 2-6 in cycle. 并重复2-6个循环。

The longest operation is point 4.2, and i dont know how to perform it faster without variables 最长的操作是4.2点,我不知道如何在没有变量的情况下更快地执行操作

Is there any faster approaches? 有没有更快的方法?

PS Sorry for my terrible english. PS对不起,我的英语不好。

You can try something like this: 您可以尝试如下操作:

update user_balance b 
  inner join (
    select b.user_id, 
           sum(case when p.buyer_id = b.user_id then p.amount else 0 end) bought, 
           sum(case when p.seller_id = b.user_id then p.amount else 0 end) sold
    from purchase p 
      inner join user_balance b 
        on p.buyer_id = b.user_id 
          or p.seller_id = b.user_id 
    group by b.user_id) q 
    on b.user_id = q.user_id 
    set b.amount = b.amount + q.sold - q.bought;

And it should do everything in a single query. 并且它应该在单个查询中完成所有操作。 You can limit the range further in the inner query if you wish. 如果需要,可以在内部查询中进一步限制范围。 SQL Fiddle seems to be down so I can't provide a live demo, but there is this: SQL Fiddle似乎已无法正常运行,因此我无法提供实时演示,但实际上是这样的:

mysql> select * from user_balance;
+---------+--------+
| user_id | amount |
+---------+--------+
|       1 |     50 |
|       2 |     50 |
|       3 |     50 |
|       4 |     50 |
+---------+--------+
4 rows in set (0.00 sec)

mysql> select * from purchase;
+-------------+-----------+----------+--------+
| purchase_id | seller_id | buyer_id | amount |
+-------------+-----------+----------+--------+
|           1 |         1 |        2 |     10 |
|           2 |         3 |        4 |     20 |
|           3 |         4 |        2 |      5 |
|           4 |         1 |        4 |      7 |
|           5 |         3 |        1 |      9 |
+-------------+-----------+----------+--------+
5 rows in set (0.00 sec)

and after the query.... 然后查询...。

mysql> update user_balance b inner join (select b.user_id, sum(case when p.buyer_id = b.user_id then p.amount else 0 end) bought, sum(case when p.seller_id = b.user_id then p.amount else 0 end) sold from purchase p inner join user_balance b on p.buyer_id = b.user_id or p.seller_id = b.user_id group by b.user_id) q on b.user_id = q.user_id set b.amount = b.amount + q.sold - q.bought;
Query OK, 4 rows affected (0.07 sec)
Rows matched: 4  Changed: 4  Warnings: 0

mysql> select * from user_balance;
+---------+--------+
| user_id | amount |
+---------+--------+
|       1 |     58 |
|       2 |     35 |
|       3 |     79 |
|       4 |     28 |
+---------+--------+
4 rows in set (0.00 sec)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM