【问题标题】:Terrible performance of CakePHP Tree updateCakePHP 树更新的糟糕表现
【发布时间】:2021-09-02 10:53:30
【问题描述】:

我在一张桌子上使用 CakePHP 的 Tree behavior 来映射一个文件系统结构。 实际文件保存在与 Amazon S3 兼容的系统上,SQL 表模仿文件夹结构,文件键中的每个“文件夹”对应一行。 随着时间的推移,这个表已经增长到包含 700K+ 行。 当尝试添加一个新文件夹或删除一个空文件夹时,会执行两个类似这样的查询:

UPDATE sys_files SET lft = ((lft - 2)) WHERE (lft  > 2443)
UPDATE sys_files SET rght = ((rght - 2)) WHERE (rght  > 2443)

每一个都需要 30 多秒的时间来运行,这给用户带来了非常不愉快的体验,用户需要等待操作完成一分钟或更长时间。有时,HTTP 调用只是超时,这更糟。

发生这种情况是因为这些查询几乎更新了(非常大的)表中的每一行,如这些结果所示。

mysql> SELECT COUNT(*) FROM sys_files;
+----------+
| COUNT(*) |
+----------+
|   713259 |
+----------+
1 row in set (0.09 sec)

mysql> SELECT COUNT(*) FROM sys_files WHERE lft  > 2443;
+----------+
| COUNT(*) |
+----------+
|   704520 |
+----------+
1 row in set (0.11 sec)

mysql> SELECT COUNT(*) FROM sys_files WHERE rght  > 2443;
+----------+
| COUNT(*) |
+----------+
|   704546 |
+----------+
1 row in set (0.11 sec)

我尝试在 lftrght 字段上添加索引,但这并没有帮助,因为缓慢的部分是 700K+ 行的实际更新,没有更新查询的 WHERE 条件。而且,添加索引并没有使性能明显变差,所以我并不担心保留或离开它......问题在于更新本身,无论有没有索引。

【问题讨论】:

  • “左右”设计很可爱,但效率不高。
  • 特别是,UPDATEing 700K 行的 any 表会很慢。由于需要更新索引和数据,添加索引会使其变慢。

标签: php mysql cakephp tree cakephp-3.0


【解决方案1】:

我尝试在 lftrght 字段上添加索引,但这并没有帮助,因为缓慢的部分是 700K+ 行的实际更新,没有更新查询的 WHERE 条件。

可能发生的情况是,索引必须在更新列 lftrght 后重新创建。

我们可以尝试使用复制表 (sf_copy) 上的索引,因此 MySQL 不会在每个 UPDATE 上重新创建它们。

例子:

CREATE TABLE sf_copy LIKE sys_files;
INSERT INTO sf_copy SELECT * FROM sys_files;

然后在sys_files_copy 表(列lftrght)上重新创建索引。

然后尝试以下操作:

UPDATE   sys_files AS sf, 
         sf_copy AS sc 
SET      sf.lft = sf.lft - 2
WHERE    sc.lft  > 2443 
         AND sc.id = sf.id;

(请注意sc.id = sf.id 部分。进行JOIN 很重要)

【讨论】:

  • 我认为不得不同时处理两个表而不是一个表会产生比它解决的问题更多的问题......首先,更新查询是由 Cake 的内部代码触发的,所以我必须跳过很多箍来改变它,因为我不能简单地编辑代码。其次,我必须为每个 CRUD 操作(不仅是删除)实现类似的更改,以保持两个表同步。最后,这意味着在涉及 lft 和 rght 字段的 sys_files 表上的搜索必须与附加表连接,因为这是这些字段的索引所在的位置。
【解决方案2】:

(这可能无法实现,因为想要控制第三方包。)

UPDATE sys_files SET lft = ((lft - 2)) WHERE (lft  > 2443)
UPDATE sys_files SET rght = ((rght - 2)) WHERE (rght  > 2443)

-->

CREATE TABLE tmp
    SELECT ((other columns)),
           IF (lft  > 2443, lft  - 2, lft )  AS lft,
           IF (rght > 2443, rght - 2, rght)  AS rght,
           ((other columns))
    FROM sys_files;
ALTER TABLE tmp ADD ((whatever indexes you had));
RENAME sys_files TO old,
       tmp TO sys_files;
DROP TABLE old;

对于 700K 行的表,这可能会明显更快,但对于 10 行的表来说速度不是很快,如果 2443 靠近表的“末端”也不会。

【讨论】:

    猜你喜欢
    • 2020-09-28
    • 2014-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 2014-11-18
    • 1970-01-01
    • 2020-03-31
    相关资源
    最近更新 更多