簡體   English   中英

為什么這個update-with-join mysql查詢這么慢?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM