Mysql 存储过程及函数优化

 1、尽量不使用自关联查询,尤其是在大数据量的时候耗时体现的非常突出。

这是原查询函数:

 1 CREATE FUNCTION get_channel_activation_count(p_channel_id  BIGINT,
 2                                                          p_date_string VARCHAR(255))
 3   RETURNS int(11)
 4   SQL SECURITY INVOKER
 5   COMMENT '******'
 6 BEGIN
 7   -- 开始时间戳、结束时间戳
 8   DECLARE var_timestamp_begin, var_timestamp_end  TIMESTAMP;
 9   DECLARE result                                  BIGINT DEFAULT 0;
10 
11   -- 检查输入参数
12   IF (ifnull(DATE_FORMAT(p_date_string, '%Y-%m-%d'), NULL) IS NULL) THEN
13     CALL pro_protreat_errorinfo(DATE_FORMAT(now(), '%Y%m%d'), '******,日期格式错误');
14     RETURN 0;
15   END IF;
16 
17   SET var_timestamp_begin = str_to_date(concat(p_date_string, ' 00:00:00'), '%Y%m%d %k:%i:%s');
18   SET var_timestamp_end = str_to_date(concat(p_date_string, ' 23:59:59'), '%Y%m%d %k:%i:%s');
19 
20   SELECT count(*)
21   INTO
22     result
23   FROM
24     (
25     SELECT T1.CHANNEL_ID
26     FROM
27       (
28       SELECT t.CHANNEL_ID
29            , t.APP_PAG_ID
30            , t.IMEI
31            , max(t.ACTIVATION_TIME) AS ACTIVATION_TIME
32            , ifnull(AI.ACTIVE_HOUR, 1) AS ACTIVE_HOUR
33            , ifnull(AI.ACTIVE_DAY, 30) AS ACTIVE_DAY
34       FROM
35         YG_PRETREAT_ACTIVATION_RECORD t
36       INNER JOIN YG_CHANNEL_APP_GD CH_APP
37       ON CH_APP.APP_BAG_ID = t.APP_PAG_ID
38       AND CH_APP.CHL_ID = t.CHANNEL_ID AND CH_APP.STATE = 1
39       INNER JOIN APP_PAG_INFO I
40       ON I.ID = t.APP_PAG_ID AND I.STATE = 1  AND I.APP_FROM IN(4,5,12)
41       INNER JOIN APP_INFO AI
42       ON AI.ID = I.APP_ID
43       WHERE
44         t.ACTIVATION_COUNT = 1
45         AND t.CHANNEL_ID = p_channel_id
46       GROUP BY
47         t.APP_PAG_ID
48       , t.IMEI
49       , t.CHANNEL_ID
50       ) T1
51     INNER JOIN (
52       SELECT t.CHANNEL_ID
53            , t.APP_PAG_ID
54            , t.IMEI
55            , t.ACTIVATION_TIME
56            , t.ACTIVATION_COUNT
57       FROM
58         YG_PRETREAT_ACTIVATION_RECORD t
59       INNER JOIN YG_CHANNEL_APP_GD CH_APP
60       ON CH_APP.APP_BAG_ID = t.APP_PAG_ID
61       AND CH_APP.CHL_ID = t.CHANNEL_ID AND CH_APP.STATE = 1
62       INNER JOIN APP_PAG_INFO APP_PAG
63       ON APP_PAG.ID = t.APP_PAG_ID
64       AND APP_PAG.STATE = 1 AND APP_PAG.APP_FROM IN(4,5,12)
65       WHERE
66         t.CREATE_TIME >= var_timestamp_begin
67         AND t.CREATE_TIME <= var_timestamp_end
68       ) T2
69     ON T2.APP_PAG_ID = T1.APP_PAG_ID
70     AND T2.IMEI = T1.IMEI
71     AND T2.CHANNEL_ID = T1.CHANNEL_ID
72     WHERE
73       T2.ACTIVATION_TIME BETWEEN date_add(T1.ACTIVATION_TIME, INTERVAL T1.ACTIVE_HOUR DAY)
74       AND date_add(T1.ACTIVATION_TIME, INTERVAL T1.ACTIVE_DAY DAY)
75     GROUP BY
76       T1.CHANNEL_ID
77     , T1.APP_PAG_ID
78     , T1.IMEI
79     ) t_ac;
80   RETURN result;
81 END

该计算函数在整个预处理过程中耗时相当久,在目前的数据量之下耗时超过5个小时...

用游标修改过后耗时直接下降到12分钟

CREATE FUNCTION get_channel_activation_count(p_channel_id  BIGINT,
                                                         p_date_string VARCHAR(255))
  RETURNS int(11)
  SQL SECURITY INVOKER
  COMMENT '******'
BEGIN -- 开始时间戳、结束时间戳
  DECLARE var_timestamp_begin, var_timestamp_end                             TIMESTAMP;
  DECLARE the_last                                                           INT DEFAULT 0;
  DECLARE result, result_tmp                                                 BIGINT DEFAULT 0;
  DECLARE var_active_time                                                    TIMESTAMP;
  DECLARE var_channel_id, var_app_pag_id, var_active_hour, var_active_day    BIGINT;

  DECLARE var_imei                                                           VARCHAR(255);

  DECLARE cur_pre_activation CURSOR FOR SELECT t.CHANNEL_ID
                                             , t.APP_PAG_ID
                                             , t.IMEI
                                             , max(t.ACTIVATION_TIME) AS ACTIVATION_TIME
                                             , ifnull(AI.ACTIVE_HOUR, 1) AS ACTIVE_HOUR
                                             , ifnull(AI.ACTIVE_DAY, 30) AS ACTIVE_DAY
                                        FROM
                                          YG_PRETREAT_ACTIVATION_RECORD t
                                        INNER JOIN YG_CHANNEL_APP_GD CH_APP
                                        ON CH_APP.APP_BAG_ID = t.APP_PAG_ID
                                        AND CH_APP.CHL_ID = t.CHANNEL_ID AND CH_APP.STATE = 1
                                        INNER JOIN APP_PAG_INFO I
                                        ON I.ID = t.APP_PAG_ID AND I.STATE = 1
                                        INNER JOIN APP_INFO AI
                                        ON AI.ID = I.APP_ID
                                        WHERE
                                          t.ACTIVATION_COUNT = 1
                                          AND t.CHANNEL_ID = p_channel_id
                                        GROUP BY
                                          t.APP_PAG_ID
                                        , t.IMEI
                                        , t.CHANNEL_ID;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET the_last = 1;

  -- 检查输入参数
  IF (ifnull(DATE_FORMAT(p_date_string, '%Y-%m-%d'), NULL) IS NULL) THEN
    CALL pro_protreat_errorinfo(DATE_FORMAT(now(), '%Y%m%d'), '******,日期格式错误');
    RETURN 0;
  END IF;

  SET var_timestamp_begin = str_to_date(concat(p_date_string, ' 00:00:00'), '%Y%m%d %k:%i:%s');
  SET var_timestamp_end = str_to_date(concat(p_date_string, ' 23:59:59'), '%Y%m%d %k:%i:%s');

  OPEN cur_pre_activation;

loop_ac:
  LOOP
    FETCH cur_pre_activation INTO var_channel_id, var_app_pag_id, var_imei, var_active_time, var_active_hour, var_active_day;
    IF (the_last = 1) THEN
      LEAVE loop_ac;
    END IF;
    SET result_tmp = 0;

    -- CALL pro_protreat_errorinfo(DATE_FORMAT(now(), '%Y%m%d'), concat('s', result_tmp, 'var_channel_id=', var_channel_id, ' var_app_pag_id', var_app_pag_id, 'var_imei', var_imei));

    SELECT count(1)
    INTO
      result_tmp
    FROM
      (
      SELECT t.CHANNEL_ID
           , t.APP_PAG_ID
           , t.IMEI
      FROM
        YG_PRETREAT_ACTIVATION_RECORD t
      INNER JOIN YG_CHANNEL_APP_GD CH_APP
      ON CH_APP.APP_BAG_ID = t.APP_PAG_ID
      AND CH_APP.CHL_ID = t.CHANNEL_ID AND CH_APP.STATE = 1
      INNER JOIN APP_PAG_INFO APP_PAG
      ON APP_PAG.ID = t.APP_PAG_ID
      AND APP_PAG.STATE = 1
      WHERE
        t.CREATE_TIME >= var_timestamp_begin
        AND t.CREATE_TIME <= var_timestamp_end
        AND t.APP_PAG_ID = var_app_pag_id
        AND t.IMEI = var_imei
        AND t.CHANNEL_ID = var_channel_id
        AND t.ACTIVATION_TIME BETWEEN date_add(var_active_time, INTERVAL var_active_hour DAY)
        AND date_add(var_active_time, INTERVAL var_active_day DAY)
      GROUP BY
        t.CHANNEL_ID
      , t.APP_PAG_ID
      , t.IMEI) a;

    SET result = result + result_tmp;

  END LOOP;
  CLOSE cur_pre_activation;

  RETURN result;
END

在此做个mark

posted @ 2013-07-22 11:49  玄剑  阅读(392)  评论(0)    收藏  举报