所以我有一个相对简单的查询,它根据WHERE为一系列输入选择存储函数的结果。完整代码如下。
让我感到困惑的是,当我通过mysql cli调用查询时,需要662秒才能返回单列的841行。现在,如果我将完全相同的代码复制/粘贴到phpmyadmin中,相同的值将在28秒内返回。
我需要做什么才能让mysql像phpmyadmin一样快地执行此查询?
我做了什么:
EXPLAIN
计划。
EXPLAIN
计划现在包含在下面。SHOW PROCESSLIST
在进程进入睡眠状态后不断计算时间。 上述问题标题和说明已经修订。 当前探索:
WHERE IN
而不是WHERE EXISTS
。
完整的查询(包括无问题的字段)
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);
QUERY EXPLAIN PLAN:
+----+-------------+-------------+--------+---------------+---------+---------+-----------------------------------------------------+------+-------------+
| 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 |
+----+--------------------+------------+----------------+---------------+---------------+---------+------------------+--------+--------------------------+
答案 0 :(得分:0)
我通过重写我的存储函数解决了这个问题。这实际上将查询时间一直缩短到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行,并具有准确的值。
答案 1 :(得分:0)
我很高兴你找到了解决方案。但是phpmyadmin,另一个php应用程序或者cli之间有不同的时间通常意味着设置在各处都不一样。根据您的时间差异,但不知道所处理数据的大小,可能是因为您的CLI缺少内存并且需要SWAP ...要验证您的不同" mysql访问环境"我建议你运行这些查询并比较结果:
show variables like max_heap_table_size #chances are you will find diff here
show variables #shows all variables
希望它可以帮助那些偶然发现这种人物的人。