[英]Why is this update-with-join mysql query so slow?
我有一個應用程序需要更新層次結構中的節點,從ID已知的特定節點向上。 我使用以下MySQL語句來執行此操作:
update node as A
join node as B
on A.lft<=B.lft and A.rgt>=B.rgt
set A.count=A.count+1 where B.id=?
該表在id上有一個主鍵,在lft和rgt上有索引。 該聲明有效,但我發現它存在性能問題。 查看相應select語句的EXPLAIN結果,我看到“B”表檢查的行數非常大(可能是整個表)。
我可以輕松地將查詢分成兩個單獨的:
select lft, rgt from node where id=?
LFT=result.lft
RGT=result.rgt
update node set count=count+1 where lft<=LFT and rgt>=RGT
但為什么原始聲明沒有達到預期的效果,我怎么需要重新制定它才能更好地發揮作用?
根據要求,這是create table的縮寫版本:
CREATE TABLE `node` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`lft` decimal(64,0) NOT NULL,
`rgt` decimal(64,0) NOT NULL,
`count` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `location` (`location`(255)),
KEY `lft` (`lft`),
KEY `rgt` (`rgt`),
) ENGINE=InnoDB
我沒有嘗試添加復合索引(實際上,我沒有現場執行此操作所需的訪問級別); 但我不知道它會如何幫助,試圖思考數據庫引擎如何嘗試解決雙重不等式。
您可以“強制”(至少高達5.5,版本5.6對優化器進行了一些改進,這可能會使這種重寫變得多余)MySQL首先通過將拆分的第一部分作為子查詢來評估表B上的條件然后使用它作為派生表並加入表A:
UPDATE node AS a
JOIN
( SELECT lft, rgt
FROM node
WHERE id = ?
) AS b
ON a.lft <= b.lft
AND a.rgt >= b.rgt
SET
a.count = a.count + 1 ;
效率仍將取決於選擇哪兩個索引來限制要更新的行。 仍然在使用這兩個索引中的任何一個之后,需要進行表查找以檢查另一列。 所以,我建議你在(lft, rgt)
和一個on (rgt, lft)
上添加一個復合索引(rgt, lft)
這樣只用一個索引來查找哪些行應該更新。
我想您正在使用嵌套集,並且此更新的效率在大表上不會很好,因為查詢具有2個范圍條件並且限制了B樹索引的效率。
我想你最大的性能問題是你正在使用的不必要的JOIN
。 你可以通過做兩個小子查詢來完成它,而不是加入兩個大表。
這是一個例子:
UPDATE node AS a
SET a.count = a.count+1
WHERE a.lft <= (SELECT lft FROM node WHERE id = ?)
AND a.rgt >= (SELECT rgt FROM node WHERE id = ?)
這只是一個建議; 我不知道它是否會奏效。
查詢的問題在於您在兩列上存在不等式。 這使得使用它們的索引非常困難 - 這反過來使得join
效率非常低。 這個想法是做兩個連接,一個用於不等式的每一邊,然后在on
條件中包含id
。 因此,只有通過兩者的節點才能通過:
UPDATE node a JOIN
(SELECT lft, rgt
FROM node
WHERE id = ?
) l
ON a.lft <= l.lft join
(SELECT lft, rgt
FROM node
WHERE id = ?
) r
on a.rgt >= r.rgt
SET a.count = a.count + 1 ;
正如我所說,我不知道這是否有效。 但您應該能夠輕松檢查查詢的explain
,以查看計划是否使用兩個不等式的索引。
我知道mysql在引用正在更新的表方面存在問題,但對我來說顯而易見的解決方案是:
update node A
set A.count=A.count+1
WHERE EXISTS (
SELECT *
FROM node B
WHERE B.id=?
AND A.lft<=B.lft and A.rgt>=B.rgt
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.