MySQL查询需要更高效

时间:2015-04-30 19:19:10

标签: mysql

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的付款行,且不存在任何付款记录。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

您的发票和付款表有多大(行)? 您可以在任何这些表上使用分区或以其他方式优化它们。 此外,我建议您查看查询计划(在您的IDE中),并检查很多成本。

答案 1 :(得分:0)

我敢打赌,由于相关的子查询(在EXISTS谓词中)正在{em> {{1}中的每个行运行,因此需要花费很长时间}表,我怀疑适当的索引是不可用的。

但在我们跳起膝盖反射之前,先添加一个索引"行列...

首先,在invoice上运行EXPLAINSELECT并抓住那个输出;这将显示查询的执行计划。

(我们非常怀疑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子句中的谓词。通过指定我们只返回paymentsinvoice_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快。