一个大的更新查询,或几个单一的更新查询,更新 MySQL 多租户数据库中的值
One big update query, or several single update queries, to update a value in MySQL multi-tenant database
我在 'point of sale' 应用程序 (PHP + MySQL) 中工作,其中的产品、销售额、产品数量必须更新(+ 或 -),具体取决于操作(sale/buy)等
每隔 sale/buy,我将操作数据(日期、客户、总计...)保存在 'invoices' table 中,并将详细信息(发票中的所有产品) 在 'invoicecontents' table.
好的,你知道了。
现在(它工作正常),我执行以下操作来保存发票并更新产品数量:
- 保存发票数据
- 迭代发票中的产品(来自 JSON)并创建单个 INSERT 查询以在第二个 table.
中保存发票内容
- 之后,保存发票和详细信息后,我会使用单个查询更新产品数量。
类似这样的事情(对于销售操作):
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;
这很好用。 当然一切都在“begin_transaction...提交”.
但是,我想知道第二种方法是否更好、更快甚至更安全安全:
- 保存发票数据
- 迭代发票中的产品(来自 JSON)并...
- 在迭代中,每个产品(每个 json 项目):
3.1.将该行保存到发票内容中 table
3.2.更新产品 table 中该产品的产品数量。
像这样,每个 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;
也许这第二种方法更简单,更可以理解,但我真的不知道这是否会导致更多(或更少)CPU,内存消耗,考虑到它是一个多租户 database/application.
我对第一种方法的问题是,在未来,我需要更新更多的字段和 tables 每个销售的产品,所以大更新查询会更大甚至不可能。
谢谢!
当然,在其他条件相同的情况下,单次查询通常比多次查询效率更高。但任何一种方法都应该有效。代码的清晰度和可读性对于长期使用 SQL 的应用程序至关重要。
如果您确实选择了多个查询,请始终以相同的顺序处理您的产品:始终按 ID
顺序对 JSON 对象中的项目列表进行排序,然后再逐一处理它们一。这将有助于避免您的事务出现死锁。
在任何一种情况下,尤其是多查询情况下,请注意为事务中所有查询中的 WHERE 子句创建高效索引。交易时间越短越好。
编辑 为获得最佳性能和最少死锁还需要做一件事。
开始事务后,立即锁定要在事务中更新的 products
中的行。 运行 这个 SELECT 查询 -- 它与您向我们展示的 UPDATE 查询非常相似。您不需要它的结果集,只需要 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;
当您提交(或回滚)事务时,FOR UPDATE 锁被释放。
ORDER BY ID
子句避免了死锁。
都没有。在 `UPDATE.
中使用 JOIN
还有
products: INDEX(IDCUSTOMER, IDPRODUCT, ACTSTOCK)
details: INDEX(IDCUSTOMER, IDPRODUCT, IDMOV)
我在 'point of sale' 应用程序 (PHP + MySQL) 中工作,其中的产品、销售额、产品数量必须更新(+ 或 -),具体取决于操作(sale/buy)等
每隔 sale/buy,我将操作数据(日期、客户、总计...)保存在 'invoices' table 中,并将详细信息(发票中的所有产品) 在 'invoicecontents' table.
好的,你知道了。
现在(它工作正常),我执行以下操作来保存发票并更新产品数量:
- 保存发票数据
- 迭代发票中的产品(来自 JSON)并创建单个 INSERT 查询以在第二个 table. 中保存发票内容
- 之后,保存发票和详细信息后,我会使用单个查询更新产品数量。
类似这样的事情(对于销售操作):
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;
这很好用。 当然一切都在“begin_transaction...提交”.
但是,我想知道第二种方法是否更好、更快甚至更安全安全:
- 保存发票数据
- 迭代发票中的产品(来自 JSON)并...
- 在迭代中,每个产品(每个 json 项目): 3.1.将该行保存到发票内容中 table 3.2.更新产品 table 中该产品的产品数量。
像这样,每个 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;
也许这第二种方法更简单,更可以理解,但我真的不知道这是否会导致更多(或更少)CPU,内存消耗,考虑到它是一个多租户 database/application.
我对第一种方法的问题是,在未来,我需要更新更多的字段和 tables 每个销售的产品,所以大更新查询会更大甚至不可能。
谢谢!
当然,在其他条件相同的情况下,单次查询通常比多次查询效率更高。但任何一种方法都应该有效。代码的清晰度和可读性对于长期使用 SQL 的应用程序至关重要。
如果您确实选择了多个查询,请始终以相同的顺序处理您的产品:始终按 ID
顺序对 JSON 对象中的项目列表进行排序,然后再逐一处理它们一。这将有助于避免您的事务出现死锁。
在任何一种情况下,尤其是多查询情况下,请注意为事务中所有查询中的 WHERE 子句创建高效索引。交易时间越短越好。
编辑 为获得最佳性能和最少死锁还需要做一件事。
开始事务后,立即锁定要在事务中更新的 products
中的行。 运行 这个 SELECT 查询 -- 它与您向我们展示的 UPDATE 查询非常相似。您不需要它的结果集,只需要 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;
当您提交(或回滚)事务时,FOR UPDATE 锁被释放。
ORDER BY ID
子句避免了死锁。
都没有。在 `UPDATE.
中使用JOIN
还有
products: INDEX(IDCUSTOMER, IDPRODUCT, ACTSTOCK)
details: INDEX(IDCUSTOMER, IDPRODUCT, IDMOV)