简体   繁体   English

一个大的更新查询,或几个单一的更新查询,更新 MySQL 多租户数据库中的一个值

[英]One big update query, or several single update queries, to update a value in MySQL multi-tenant database

I'm working in a 'point of sale' application (PHP + MySQL), with products, sales, product quantity that have to be updated (+ or -) depending on the operation (sale/buy), etc.我正在“销售点”应用程序(PHP + MySQL)中工作,根据操作(销售/购买)等必须更新(+ 或 -)的产品、销售、产品数量。

On every sale/buy, I save the operation data (date, customer, totals...) in an 'invoices' table, and the details (all products in the invoice) in a 'invoicecontents' table.在每次销售/购买时,我将操作数据(日期、客户、总计...)保存在“发票”表中,并将详细信息(发票中的所有产品)保存在“发票内容”表中。

Ok, you got it.好的,你明白了。

Now (and it works fine), I do the following to save the invoice and update products quantity:现在(并且工作正常),我执行以下操作以保存发票并更新产品数量:

  1. Save the invoice data保存发票数据
  2. Iterate the products in the invoice (from a JSON) and create a single INSERT query to save the invoice contents in second table.迭代发票中的产品(来自 JSON)并创建单个 INSERT 查询以将发票内容保存在第二个表中。
  3. AFTER THAT, once the invoice and details are saved, then I update products quantities WITH A SINGLE QUERY.之后,一旦保存了发票和详细信息,我就会使用一个查询更新产品数量。

Something like this (for a sale operation):像这样(对于销售操作):

UPDATE products a 
   SET QUANTITY = QUANTITY -
         (SELECT sum(QUANTITY) 
            FROM details b 
           WHERE IDPRODUCT = a.ID   
             and IDCUSTOMER = 4 
             and IDMOV = 615 
             and IDPRODUCT <> -1)
 where ID in 
         (SELECT IDPRODUCT 
            FROM details b 
           WHERE b.IDPRODUCT = a.ID 
             and IDCUSTOMER = 4 
             and IDMOV = 615 
             and IDARTICULO <> -1) 
   and IDCUSTOMER = 4 
   and a.ACTSTOCK = 1;

This works fine.这工作正常。 Of course all is in a "begin_transaction...commit" .当然,一切都在 "begin_transaction...commit" 中

HOWEVER, I would like to know if this second method is better, faster or even more secure :但是,我想知道第二种方法是否更好、更快或更安全

  1. Save the invoice data保存发票数据
  2. Iterate the products in the invoice (from a JSON) and...迭代发票中的产品(来自 JSON)并...
  3. Inside the iteration, for each product (each json item): 3.1.在迭代内部,对于每个产品(每个 json 项目): 3.1。 save that line into the invoice contents table 3.2.将该行保存到发票内容表 3.2 中。 update that product quantity in the products table for THAT product.更新产品表中该产品的产品数量。

Something like this, for each product/item:像这样,对于每个产品/项目:

INSERT INTO detailtable
(IDCUSTOMER,IDPRODUCT,QUANTITY......)
VALUES
(4,615,5);

UPDATE products 
SET QUANTITY = QUANTITY - 5
WHERE 
    IDPRODUCT = 615   
    and IDCUSTOMER = 4
    and ACTSTOCK = 1;

Maybe this second approach is simpler and more undertandable , but I really don't know if this will cause more (or less) CPU, memory consumption, taking into account that it is a multi-tenant database/application.也许这第二种方法更简单,更容易理解,但我真的不知道这是否会导致更多(或更少)CPU、内存消耗,考虑到它是一个多租户数据库/应用程序。

The problem I have with the first method is that, in the future, I will need to update more fields and tables with each product sold, so the big update query will be even bigger and even not possible.我对第一种方法的问题是,将来我需要为每个销售的产品更新更多的字段和表,因此大更新查询将更大甚至不可能。

Thanks!谢谢!

Of course, single queries are generally more efficient than multiple queries, all other things being equal.当然,在所有其他条件相同的情况下,单个查询通常比多个查询更有效。 But either approach should work.但任何一种方法都应该有效。 Clarity and readability of code are vital to long-lived SQL-using applications.代码的清晰性和可读性对于长期使用 SQL 的应用程序至关重要。

If you do choose multiple queries, always process your products in the same order: always sort the list of items in your JSON objects in ID order before working through them one-by-one.如果您确实选择了多个查询,请始终以相同的顺序处理您的产品:始终按照ID顺序对 JSON 对象中的项目列表进行排序,然后再一一处理它们。 This will help avoid deadlocks in your transactions.这将有助于避免事务中的死锁。

In either case, but especially the multi-query case, take care to create efficient indexes for the WHERE clauses in all the queries within your transactions.在任一情况下,尤其是多查询情况,请注意为事务中所有查询中的 WHERE 子句创建有效索引。 The less time a transaction takes, the better.交易花费的时间越少越好。

Edit One more thing to do for best performance and fewest deadlocks.编辑为获得最佳性能和最少死锁而要做的另一件事。

Right after you begin your transaction, lock the rows in products you want to update in the transaction.在您开始交易后,立即锁定要在交易中更新的products的行。 Run this SELECT query -- it is very similar to the UPDATE query you showed us.运行这个 SELECT 查询——它与您向我们展示的 UPDATE 查询非常相似。 You don't need its resultset, just the FOR UPDATE clause.您不需要它的结果集,只需要FOR UPDATE子句。

SELECT COUNT(ID) FROM (
    SELECT ID 
      FROM products
     WHERE ID in 
             (SELECT IDPRODUCT 
                FROM details b 
               WHERE b.IDPRODUCT = a.ID 
                 and IDCUSTOMER = 4 
                 and IDMOV = 615 
                 and IDARTICULO <> -1) 
       
       and IDCUSTOMER = 4 
       and a.ACTSTOCK = 1
     ORDER BY ID
       FOR UPDATE
) subq;

The FOR UPDATE locks are released when you COMMIT (or ROLLBACK) the transaction.当您提交(或回滚)事务时,会释放 FOR UPDATE 锁。

The ORDER BY ID clause avoids deadlocks. ORDER BY ID子句避免死锁。

Neither.两者都不。 Use a JOIN in the `UPDATE.使用JOIN在`UPDATE。

Also

products: INDEX(IDCUSTOMER, IDPRODUCT, ACTSTOCK)
details:  INDEX(IDCUSTOMER, IDPRODUCT, IDMOV)

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

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