所以我有一个相对简单的查询,它根据 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
在进程进入休眠状态后会继续计算时间。 上面的问题标题和描述已被修改。
- 结果: mysql cli 在 661 秒内返回值,这可能与 php cli 的速度相同。我刚刚意识到
当前探索:
- 编辑存储的函数,以便使用
WHERE EXISTS
而不是使用WHERE IN
。
整个查询:(包括无问题的字段)
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/