2014-12-03 146 views
0

所以我有一个相对简单的查询,它根据WHERE为一系列输入选择存储函数的结果。完整的代码如下。查询在phpmyadmin中需要28秒,但mysql命令行需要662秒

什么是我当我通过mysql cli调用查询时,需要662秒才能返回一列中的841行。现在,如果我将相同的代码复制/粘贴到phpmyadmin中,相同的值将在28秒内返回。

我需要做什么才能使mysql像phpmyadmin一样快速执行此查询?

什么我已经尝试过:

  • 证实,双方的phpmyadmin和PHP CLI使用相同EXPLAIN计划。
    • EXPLAIN计划现包含在下面。
  • 已验证phpmyadmin和php cli都以同一用户身份执行查询。
  • 测试mysql cli是否比php cli有更好的性能。
    • 结果: mysql cli在661sec返回值,这可能与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 

功能EXPLAIN PLAN:

+----+--------------------+------------+----------------+---------------+---------------+---------+------------------+--------+--------------------------+ 
| 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

只是一个想法,但它可能是不同的RAM分配或类似的东西? – Salketer 2014-12-04 15:22:01

+0

您能否从'explain'方法提供执行计划?还有一些'mysqli'代码? – 2014-12-04 15:22:36

+0

你在执行这个查询的地方在你的php函数中执行任何其他动作吗? – MTahir 2014-12-04 15:39:28

回答

0

我通过重写我的存储功能解决了这个问题。这实际上将查询时间一直减少到1。19sec,所以我实际上是由它甚至比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行。

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 

希望它可以帮助那些偶然发现这种数字的人。