INSERT INTO payments (invoice_id)
SELECT id
FROM invoice
WHERE NOT EXISTS
(SELECT invoice_id
FROM payments
WHERE payments.invoice_id = invoice.id)
大约需要35秒。生产中有时候在创建发票时不会创建付款条目。我需要手动创建仅包含发票的invoice_id的付款行,且不存在任何付款记录。
非常感谢任何帮助。
答案 0 :(得分:0)
您的发票和付款表有多大(行)? 您可以在任何这些表上使用分区或以其他方式优化它们。 此外,我建议您查看查询计划(在您的IDE中),并检查很多成本。
答案 1 :(得分:0)
我敢打赌,由于相关的子查询(在EXISTS
谓词中)正在{em> {{1}中的每个行运行,因此需要花费很长时间}表,我怀疑适当的索引是不可用的。
但在我们跳起膝盖反射之前,先添加一个索引"行列...
首先,在invoice
上运行EXPLAIN
。 SELECT
并抓住那个输出;这将显示查询的执行计划。
(我们非常怀疑EXPLAIN SELECT ...
速度慢,而且实际上SELECT
实际上并不是因为性能陷入困境可怕的INSERT触发器等等。)
我建议重新编写查询以使用反连接模式。 (这不是灵丹妙药,但有时候我们可以获得很多更好的性能,而这主要取决于是否有合适的索引。)
INSERT
这将从 SELECT i.id
FROM invoice i
LEFT
JOIN payments p
ON p.invoice_id = i.id
WHERE p.invoice_id IS NULL
返回所有行,以及来自invoice
的所有匹配行。 payments
关键字使其成为外部联接;这意味着该查询还会返回LEFT
中没有invoice
匹配行的行。
"技巧"是WHERE子句中的谓词。通过指定我们只返回payments
中invoice_id
为NULL的行,我们会过滤掉payments
中匹配行的所有invoice
。
我们可以使用该查询运行payments
。至少,我们期望看到查询有效地使用带有EXPLAIN SELECT ...
前导列的索引,并且"使用索引"在Extra列中。
如果内存为我服务,我认为这不能直接在invoice_id
中使用,因为查询引用了同一个表。解决方法是将此查询引用为内联视图...
INSERT INTO payments
这确实增加了一些开销,实现了派生表。但对于相对较小的一组来说,它不应该太糟糕。
该查询可以作为SELECT s.id
FROM ( SELECT i.id
FROM invoice i
LEFT
JOIN payments p
ON p.invoice_id = i.id
WHERE p.invoice_id IS NULL
) s
没有看到EXPLAIN输出和表定义(包括索引),我们真的只是猜测MySQL在做什么。我们真的想看看SELECT如何执行,INSERT的运行速度比SELECT快。