mysql - 在 phpmyadmin 中查询需要 28 秒,但 mysql 命令行需要 662 秒

标签 mysql phpmyadmin

所以我有一个相对简单的查询,它根据 WHERE 为一系列输入选择存储函数的结果。完整代码如下。

令我困惑的是,当我通过 mysql cli 调用查询时,需要 662 秒才能返回单列的 841 行。现在,如果我将完全相同的代码复制/粘贴到 phpmyadmin 中,则会在不到 28 秒的时间内返回相同的值。

我需要做什么才能让 mysql 和 phpmyadmin 一样快地执行这个查询?

我已经尝试过的:

  • 已验证 phpmyadmin 和 php cli 使用相同的 EXPLAIN 计划。
    • EXPLAIN 计划现已包含在下面。
  • 已验证 phpmyadmin 和 php cli 是否以同一用户身份执行查询。
  • 测试了mysql cli是否比php cli性能更好。
    • 结果: mysql cli 在 661 秒内返回值,这可能与 php cli 的速度相同。我刚刚意识到 SHOW PROCESSLIST 在进程进入休眠状态后会继续计算时间。 上面的问题标题和描述已被修改。

当前探索:

整个查询:(包括无问题的字段)

SELECT 
    EC_ITM_PULL.SKU_NUM, 
    EC_ITM_PULL.COLOR_CD, 
    GM_SKU.COLOR_DES, 
    GM_ITM.DES1, 
    GM_ITM.DES2, 
    CUSTOM.EC_GET_ONHAND(SUBSTRING(GM_SKU.SKU_NUM, 1, 9), GM_SKU.COLOR_CD) OH, 
    UPPER(EC_ITM_PULL.ITEM_PULLED_INIT) INIT, 
    CUSTOM.EC_MOST_RECENT_EVENT(SUBSTRING(GM_SKU.SKU_NUM, 1, 9), GM_SKU.COLOR_CD, 'E') EVENT_CD 
FROM 
    EC_ITM_PULL, 
    GM_MERCH.GM_SKU, 
    GM_INV.GM_ITM, 
    EC_ITM 
WHERE 
        EC_ITM.SKU_NUM = EC_ITM_PULL.SKU_NUM 
    AND EC_ITM_PULL.COLOR_CD = EC_ITM.COLOR_CD 
    AND EC_ITM_PULL.ITEM_PULLED IS NOT NULL 
    AND GM_ITM.ITM_CD = SUBSTRING(EC_ITM.SKU_NUM, 1, 9) 
    AND EC_ITM.SKU_NUM = GM_SKU.SKU_NUM 
    AND EC_ITM.TO_STUDIO IS NULL 
    AND GM_ITM.ITM_CD = SUBSTRING(EC_ITM_PULL.SKU_NUM, 1, 9);

查询解释计划:

+----+-------------+-------------+--------+---------------+---------+---------+-----------------------------------------------------+------+-------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                                                 | rows | Extra       |
+----+-------------+-------------+--------+---------------+---------+---------+-----------------------------------------------------+------+-------------+
|  1 | SIMPLE      | EC_ITM_PULL | ALL    | SKU_NUM       | NULL    | NULL    | NULL                                                | 2100 | Using where |
|  1 | SIMPLE      | GM_ITM      | eq_ref | PRIMARY       | PRIMARY | 38      | func                                                |    1 | Using where |
|  1 | SIMPLE      | GM_SKU      | ref    | SKU_NUM       | SKU_NUM | 38      | CUSTOM.EC_ITM_PULL.SKU_NUM                          |    1 |             |
|  1 | SIMPLE      | EC_ITM      | eq_ref | PRIMARY       | PRIMARY | 58      | GM_MERCH.GM_SKU.SKU_NUM,CUSTOM.EC_ITM_PULL.COLOR_CD |    1 | Using where |
+----+-------------+-------------+--------+---------------+---------+---------+-----------------------------------------------------+------+-------------+

有问题的存储函数:

CREATE DEFINER=`root`@`localhost` FUNCTION `EC_GET_ONHAND`(`N_ITM_CD` VARCHAR(12), `N_COLOR_CD` VARCHAR(6)) RETURNS smallint(5)
BEGIN
    DECLARE TOTALOH SMALLINT(5);

    IF N_COLOR_CD IS NULL THEN SELECT IFNULL(SUM(IFNULL(RESERVE_QTY,0)+IFNULL(AVAIL_QTY,0)),0)
    INTO TOTALOH FROM GM_INV.GM_INV_LOC
    WHERE SKU_NUM 
    IN (
        SELECT SKU_NUM 
        FROM GM_MERCH.GM_SKU 
        WHERE ITM_CD = N_ITM_CD AND COLOR_CD IS NULL
    ) 
    AND (
        (
            (
                STORE_CD='85' 
                OR STORE_CD='95'
            ) 
            AND LOC_CD='STG72'
        ) 
        OR (
           (
               STORE_CD='72'
           ) 
           AND LOC_CD='RCV'
        )
    );

    ELSE SELECT IFNULL(SUM(IFNULL(RESERVE_QTY,0)+IFNULL(AVAIL_QTY,0)),0)
    INTO TOTALOH 
    FROM GM_INV.GM_INV_LOC
    WHERE SKU_NUM
    IN (
        SELECT SKU_NUM 
        FROM GM_MERCH.GM_SKU 
        WHERE ITM_CD = N_ITM_CD 
        AND COLOR_CD = N_COLOR_CD)
        AND (
            (
                (
                    STORE_CD='85' 
                    OR STORE_CD='95'
                ) 
                AND LOC_CD='STG72'
            ) 
            OR (
                (
                    STORE_CD='72'
                ) 
                AND LOC_CD='RCV'
            )
        );

    END IF;

    RETURN TOTALOH;
END

功能解释计划:

+----+--------------------+------------+----------------+---------------+---------------+---------+------------------+--------+--------------------------+
| id | select_type        | table      | type           | possible_keys | key           | key_len | ref              | rows   | Extra                    |
+----+--------------------+------------+----------------+---------------+---------------+---------+------------------+--------+--------------------------+
|  1 | PRIMARY            | GM_INV_LOC | ALL            | NULL          | NULL          | NULL    | NULL             | 509791 | Using where              |
|  2 | DEPENDENT SUBQUERY | GM_SKU     | index_subquery | SKU_ITM_COLOR | SKU_ITM_COLOR | 97      | func,const,const |      1 | Using index; Using where |
+----+--------------------+------------+----------------+---------------+---------------+---------+------------------+--------+--------------------------+

最佳答案

我通过重写我的存储函数解决了这个问题。这实际上将查询时间减少到了 1.19 秒,所以我实际上让它比 phpmyadmin 更快 =)

首先,我采纳了问题中链接文章的建议并编辑了这部分:

WHERE SKU_NUM 
    IN (
        SELECT SKU_NUM 
        FROM GM_MERCH.GM_SKU 
        WHERE ITM_CD = N_ITM_CD AND COLOR_CD IS NULL
    ) 

对此:

WHERE EXISTS 
    (
        SELECT 1 
        FROM GM_MERCH.GM_SKU, GM_INV.GM_INV_LOC
        WHERE 
            ITM_CD = N_ITM_CD 
        AND COLOR_CD IS NULL
        AND GM_INV_LOC.SKU_NUM = GM_MERCH.SKU_NUM
    ) 

这将查询的执行时间减少到不到 180 秒,但导致函数返回不正确的值,因为它对子查询中的每一行重复添加。

然后我突然想到也许我根本不应该使用子查询。我重写了函数中的查找,如下所示:

SELECT IFNULL(SUM(IFNULL(RESERVE_QTY,0)+IFNULL(AVAIL_QTY,0)),0)
    INTO TOTALOH FROM GM_INV.GM_INV_LOC, GM_MERCH.SKU_NUM
    WHERE 
        ITM_CD = N_ITM_CD 
    AND COLOR_CD IS NULL
    AND GM_INV_LOC.SKU_NUM = GM_SKU.SKU_NUM
    AND (
        (
            (
                STORE_CD='85' 
                OR STORE_CD='95'
            ) 
            AND LOC_CD='STG72'
        ) 
        OR (
           (
               STORE_CD='72'
           ) 
           AND LOC_CD='RCV'
        )
    );

整个大型查询现在可在 1.19 秒内返回 841 行并提供准确值。

关于mysql - 在 phpmyadmin 中查询需要 28 秒,但 mysql 命令行需要 662 秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27282823/

相关文章:

mysql - sql 查询回调中的 res.sendFile

mysql - 在循环内使用 sequelize 更新多行

phpmyadmin http 500 error.. No such file or directory in/usr/share/php/Symfony/Component/Cache/autoload.php 第 6 行

mysql - phpmyadmin 下划线赋予错误数据库权限

php - SQL 棘手的嵌套请求

mysql - 按重复列删除条目

Mysql - 从行中获取数据并将其复制到另一行

mysql - 在 MySQL 中将转义的 UTF-16(JSON 实体)转换回正常的 UTF-8

php - 查询不返回任何记录,但 phpmyadmin 返回

php - MySQL 表更新错误