MySQL SQL优化——分片搜索
DELIMITER $$ DROP PROCEDURE IF EXISTS `test_release`.`Sp_JP_A_NotifyBegin`$$ CREATE DEFINER=`encysys48`@`%` PROCEDURE `Sp_JP_A_NotifyBegin`(
OUT v_Result varchar(10),
OUT v_OrderID varchar(500),
OUT v_HFserialid varchar(500),
OUT v_ChargeSerialID varchar(500),
OUT v_ErrorCode varchar(100),
OUT v_FullMoney varchar(200),
OUT v_PlatId varchar(200),
OUT v_NotifyCount varchar(4),
OUT v_PHONERESMONEY varchar(200),
OUT v_AGENTID varchar(500)
)
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
label2: BEGIN
DECLARE l_hforderid varchar(30);
DECLARE l_hfserialid varchar(30);
DECLARE l_errorcode varchar(10);
DECLARE l_charserialid varchar(50);
DECLARE l_fullmoney decimal(10, 2);
DECLARE l_platid int(10);
DECLARE l_notofynum int(4);
DECLARE l_status int(4);
DECLARE l_increce int(10);
DECLARE l_nowtime timestamp;
DECLARE l_phoneresmoney varchar(30);
DECLARE l_agentid varchar(30);
DECLARE l_CheckCode varchar(100);
DECLARE l_PlatCheckResult varchar(10);
DECLARE l_stop_flag int(2);
DECLARE l_flag int(2);
DECLARE l_cursorEmpty int(2) DEFAULT 0; #游标是否为空标记位,0-为空 ;1-不为空
DECLARE l_cursorOpen int(2) DEFAULT 0; #游标是否打开标记位,0-没打开;1-已打开
DECLARE l_cursorClose int(2) DEFAULT 0; #游标是否关闭标记位,0-未关闭;1-已关闭 #定义游标
DECLARE cur_notify CURSOR FOR
SELECT a.hf_serialid
FROM (SELECT hf_serialid
FROM jp_fullnote s
WHERE charge_status IN (0, 3)
AND (notify_flag = 1 OR (notify_flag = 2 AND DATE_ADD(end_time, INTERVAL 3 MINUTE) < l_nowtime))
AND DATE_ADD(begin_time, INTERVAL 48 HOUR) > l_nowtime
AND DATE_ADD(begin_time, INTERVAL 3 HOUR) < l_nowtime
ORDER BY DATE_ADD(end_time, INTERVAL notify_count MINUTE) ASC
) a
LIMIT 0, 10; #其他异常
DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION, NOT FOUND
BEGIN
#先判断是否需要关闭游标:如果游标“已打开且未关闭”,则需要关闭
IF l_cursorOpen = 1 AND l_cursorClose = 0 THEN
CLOSE cur_notify;
END IF; IF l_cursorEmpty = 0 THEN
SET v_OrderID = '-1';
SET v_HFserialid = '-1';
SET v_ErrorCode = '-1';
SET v_FullMoney = '-1';
SET v_PlatId = '-1';
SET v_result = '';
SET v_PHONERESMONEY = '-1';
SET v_AGENTID = '-1';
ROLLBACK;
ELSE
SET v_result = '';
SET v_notifycount = l_increce;
COMMIT;
END IF;
END; #赋初始值
SET v_result = '';
SET v_OrderID = '';
SET v_HFserialid = '';
SET v_ChargeSerialID = '';
SET v_ErrorCode = '';
SET v_FullMoney = '';
SET v_PlatId = '';
SET l_notofynum = 0;
SET l_increce = 0;
SET v_PHONERESMONEY = '';
SET v_AGENTID = '';
SET l_nowtime = now();
SET l_stop_flag = 0;
SET l_flag = 0; #自动流程监控
SELECT CONCAT('ChPlat', t.sys_id, '_A8002_NotifyHF') INTO l_CheckCode
FROM jp_sysplat t;
CALL Sp_MO_PlatAutoCheck(l_CheckCode, '3B', l_PlatCheckResult); #使用游标
BEGIN
DECLARE EXIT HANDLER FOR SQLSTATE ''
BEGIN
SET l_stop_flag = 1;
END; #打开游标
OPEN cur_notify;
SET l_cursorOpen = 1; #打开游标后,把游标打开的标记位置为1,表示已打开 FETCH cur_notify INTO l_hfserialid;
#进入游标循环
label1: WHILE l_stop_flag < 1 DO
#每次循环计数
SET l_cursorEmpty = l_cursorEmpty + 1; SELECT charge_status,ERROR_CODE,hf_orderid,hf_serialid,finish_money,
f.senderobj,charge_serialid,PHONE_RESMONEY,AGENT_ID
INTO l_status, l_errorcode, l_hforderid, l_hfserialid, l_fullmoney,
l_platid, l_charserialid, l_phoneresmoney, l_agentid
FROM jp_fullnote f
WHERE hf_serialid = l_hfserialid; IF l_status = 3 THEN
SET l_fullmoney = 0;
END IF; BEGIN
DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION, NOT FOUND
SET l_flag = 1; SELECT notify_return_code
INTO l_errorcode
FROM jp_return_code r
WHERE r.error_code = l_errorcode;
END; IF l_flag = 1 THEN
FETCH cur_notify INTO l_hfserialid;
ITERATE label1;
END IF; SET v_OrderID = CONCAT(v_OrderID, l_hforderid, ',');
SET v_HFserialid = CONCAT(v_HFserialid, l_hfserialid, ',');
SET v_ChargeSerialID = CONCAT(v_ChargeSerialID, l_charserialid, ',');
SET v_ErrorCode = CONCAT(v_ErrorCode, l_errorcode, ',');
SET v_FullMoney = CONCAT(v_FullMoney, l_fullmoney, ',');
SET v_PlatId = CONCAT(v_PlatId, l_platid, ','); IF l_phoneresmoney > 10000 THEN
SET v_PHONERESMONEY = CONCAT(v_PHONERESMONEY, '', ',');
ELSE
SET v_PHONERESMONEY = CONCAT(v_PHONERESMONEY, l_phoneresmoney, ',');
END IF; SET v_AGENTID = CONCAT(v_AGENTID, l_agentid, ','); UPDATE jp_fullnote
SET notify_flag = 2,
notify_count = notify_count + 1,
end_time = l_nowtime
WHERE hf_serialid = l_hfserialid; SET l_increce = l_increce + 1;
COMMIT; FETCH cur_notify INTO l_hfserialid;
END WHILE label1;
END; #关闭游标
CLOSE cur_notify;
SET l_cursorClose = 1; #关闭游标后,把游标关闭的标记位置为1,表示已关闭 #判断游标是否为空
IF l_cursorEmpty = 0 THEN
SET v_OrderID = '-1';
SET v_HFserialid = '-1';
SET v_ChargeSerialID = '-1';
SET v_ErrorCode = '-1';
SET v_FullMoney = '-1';
SET v_PlatId = '-1';
SET v_PHONERESMONEY = '-1';
SET v_AGENTID = '-1';
LEAVE label2;
END IF; SET v_NotifyCount = l_increce;
SET v_result = '';
COMMIT;
END;
END$$ DELIMITER ;
优化前
DELIMITER $$ DROP PROCEDURE IF EXISTS `encysys48`.`sp_jp_a_notifyBegin_acc`$$ CREATE DEFINER=`encysys48`@`%` PROCEDURE `sp_jp_a_notifyBegin_acc`(
IN v_num VARCHAR(2), #流水号最后一位除10,所得余数
OUT v_Result varchar(10), #结果码
OUT v_OrderID varchar(500), #订单号
OUT v_HFserialid varchar(500), #话费流水号
OUT v_ChargeSerialID varchar(500), #对端流水
OUT v_ErrorCode varchar(100), #结果码
OUT v_FullMoney varchar(200), #充值金额
OUT v_PlatId varchar(200), #中心平台号
OUT v_NotifyCount varchar(4), #数量
OUT v_PHONERESMONEY varchar(200), #充值后手机余额
OUT v_AGENTID varchar(500)
)
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
label2: BEGIN
DECLARE l_num INT(2); #流水号最后一位除10,所得余数
DECLARE l_hforderid varchar(30);
DECLARE l_hfserialid varchar(30);
DECLARE l_errorcode varchar(10);
DECLARE l_charserialid varchar(50);
DECLARE l_fullmoney decimal(10, 2);
DECLARE l_platid int(10);
DECLARE l_notofynum int(4);
DECLARE l_status int(4);
DECLARE l_increce int(10);
DECLARE l_nowtime timestamp;
DECLARE l_phoneresmoney varchar(20);
DECLARE l_agentid varchar(30);
DECLARE l_CheckCode varchar(100);
DECLARE l_PlatCheckResult varchar(10);
DECLARE l_stop_flag int(2);
DECLARE l_flag int(2);
DECLARE l_str VARCHAR(50);
DECLARE l_cursorEmpty int(2) DEFAULT 0; #游标是否为空标记位,0-为空 ;1-不为空
DECLARE l_cursorOpen int(2) DEFAULT 0; #游标是否打开标记位,0-没打开;1-已打开
DECLARE l_cursorClose int(2) DEFAULT 0; #游标是否关闭标记位,0-未关闭;1-已关闭
declare l_search_times INT(2) DEFAULT 0; #循环执行游标的次数
DECLARE l_start_time TIMESTAMP; #游标搜索的起始时间
DECLARE l_end_time TIMESTAMP; #游标搜索的结束时间
#定义游标
DECLARE cur_notify CURSOR FOR
SELECT a.hf_serialid
FROM (SELECT hf_serialid
FROM jp_fullnote s
WHERE charge_status IN (0, 3)
AND (notify_flag = 1 OR (notify_flag = 2 AND DATE_ADD(end_time, INTERVAL 3 MINUTE) < l_nowtime))
AND MOD(SUBSTRING(hf_serialid, CHAR_LENGTH(hf_serialid), 1), 10) = l_num
AND begin_time >= l_start_time and begin_time < l_end_time
ORDER BY DATE_ADD(end_time, INTERVAL notify_count MINUTE) ASC
) a
LIMIT 0, 10; #其他异常
DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION, NOT FOUND
BEGIN
#先判断是否需要关闭游标:如果游标“已打开且未关闭”,则需要关闭
IF l_cursorOpen = 1 AND l_cursorClose = 0 THEN
CLOSE cur_notify;
END IF; IF l_cursorEmpty = 0 THEN
SET v_OrderID = '-1';
SET v_HFserialid = '-1';
SET v_ErrorCode = '-1';
SET v_FullMoney = '-1';
SET v_PlatId = '-1';
SET v_result = '';
SET v_PHONERESMONEY = '-1';
SET v_AGENTID = '-1';
ROLLBACK;
ELSE
SET v_result = '';
SET v_notifycount = l_increce;
COMMIT;
END IF;
CALL sp_SN_dbwarning(1, 'Sp_JP_A_NotifyBegin_Acc', '', "", NULL, NULL);
END; #赋初始值
SET v_result = '';
SET v_OrderID = '';
SET v_HFserialid = '';
SET v_ChargeSerialID = '';
SET v_ErrorCode = '';
SET v_FullMoney = '';
SET v_PlatId = '';
SET l_notofynum = 0;
SET l_increce = 0;
SET v_PHONERESMONEY = '';
SET v_AGENTID = '';
SET l_nowtime = now();
SET l_stop_flag = 0;
SET l_flag = 0;
SET l_num = v_Num;
#自动流程监控
BEGIN
DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION, NOT FOUND SET l_CheckCode = 'unknown_A80??_Charge_General?';
SELECT
CASE v_Num
WHEN 0 THEN '_A8040_Charge_General0'
WHEN 1 THEN '_A8041_Charge_General1'
WHEN 2 THEN '_A8042_Charge_General2'
WHEN 3 THEN '_A8043_Charge_General3'
WHEN 4 THEN '_A8044_Charge_General4'
WHEN 5 THEN '_A8045_Charge_General5'
WHEN 6 THEN '_A8046_Charge_General6'
WHEN 7 THEN '_A8047_Charge_General7'
WHEN 8 THEN '_A8048_Charge_General8'
WHEN 9 THEN '_A8049_Charge_General9' ELSE '_A80??_Charge_General?' END INTO l_str
FROM DUAL;
SELECT CONCAT('ChPlat', t.sys_id, l_str) INTO l_CheckCode
FROM jp_sysplat t;
CALL Sp_MO_PlatAutoCheck(l_CheckCode, '3B', l_PlatCheckResult);
END;
set l_start_time = now();
#使用游标
looplabel: while ((l_increce < 10) and (l_search_times < 18)) do
set l_end_time = l_start_time;
set l_start_time = DATE_ADD(l_end_time, INTERVAL -10 MINUTE);
set l_stop_flag = 0;
BEGIN
DECLARE EXIT HANDLER FOR SQLSTATE ''
BEGIN
SET l_stop_flag = 1;
END;
#打开游标
OPEN cur_notify;
SET l_cursorOpen = 1; #打开游标后,把游标打开的标记位置为1,表示已打开 FETCH cur_notify INTO l_hfserialid;
INSERT INTO w_help(char_content) VALUES(l_increce);
#进入游标循环
label1: WHILE l_stop_flag < 1 and l_increce < 10 DO
#每次循环计数
SET l_cursorEmpty = l_cursorEmpty + 1; SELECT charge_status,ERROR_CODE,hf_orderid,hf_serialid,finish_money,
senderobj,charge_serialid,PHONE_RESMONEY,AGENT_ID
INTO l_status, l_errorcode, l_hforderid, l_hfserialid, l_fullmoney,
l_platid, l_charserialid, l_phoneresmoney, l_agentid
FROM jp_fullnote f
WHERE hf_serialid = l_hfserialid; #判断订单是否是失败
IF l_status = 3 THEN
SET l_fullmoney = 0;
END IF; #获取错误码
BEGIN
DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION, NOT FOUND
SET l_flag = 1; SELECT notify_return_code
INTO l_errorcode
FROM jp_return_code r
WHERE r.error_code = l_errorcode;
END; IF l_flag = 1 THEN
FETCH cur_notify INTO l_hfserialid;
ITERATE label1;
END IF; #拼接参数
SET v_OrderID = CONCAT(v_OrderID, l_hforderid, ',');
SET v_HFserialid = CONCAT(v_HFserialid, l_hfserialid, ',');
SET v_ChargeSerialID = CONCAT(v_ChargeSerialID, l_charserialid, ',');
SET v_ErrorCode = CONCAT(v_ErrorCode, l_errorcode, ',');
SET v_FullMoney = CONCAT(v_FullMoney, l_fullmoney, ',');
SET v_PlatId = CONCAT(v_PlatId, l_platid, ','); IF l_phoneresmoney > 10000 THEN
SET v_PHONERESMONEY = CONCAT(v_PHONERESMONEY, '', ',');
ELSE
SET v_PHONERESMONEY = CONCAT(v_PHONERESMONEY, l_phoneresmoney, ',');
END IF; SET v_AGENTID = CONCAT(v_AGENTID, l_agentid, ','); UPDATE jp_fullnote
SET notify_flag = 2,
notify_count = notify_count + 1,
end_time = l_nowtime
WHERE hf_serialid = l_hfserialid; SET l_increce = l_increce + 1;
INSERT INTO w_help(char_content) VALUES(l_increce);
COMMIT; #进入下一次循环
FETCH cur_notify INTO l_hfserialid;
END WHILE label1;
END;
#关闭游标
CLOSE cur_notify;
SET l_cursorClose = 1; #关闭游标后,把游标关闭的标记位置为1,表示已关闭
set l_search_times = l_search_times + 1;
INSERT INTO w_help(char_content) VALUES(l_search_times);
END WHILE looplabel;
#判断游标是否为空
IF l_cursorEmpty = 0 THEN
SET v_OrderID = '-1';
SET v_HFserialid = '-1';
SET v_ChargeSerialID = '-1';
SET v_ErrorCode = '-1';
SET v_FullMoney = '-1';
SET v_PlatId = '-1';
SET v_PHONERESMONEY = '-1';
SET v_AGENTID = '-1';
LEAVE label2;
END IF; SET v_NotifyCount = l_increce;
insert into w_help(char_content) values(l_increce);
SET v_result = '';
COMMIT;
END;
END$$ DELIMITER ;
优化后
优化的核心是:
优化前,搜索三小时以内的满足条件的订单,十条;
优化后,搜索十分钟以内的,满足条件的,搜索结果数目大于10,返回10条搜素结果;
搜索结果数目小于10,继续搜索10~20分钟之间的,总共之和大于10,返回结果;
总共结果小于10,继续搜索20~30分钟之间的。
这样,即使搜索三小时以内的,速度也明显的快。
MySQL SQL优化——分片搜索的更多相关文章
- mysql sql优化实例
mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...
- Mysql SQL优化&执行计划
SQL优化准则 禁用select * 使用select count(*) 统计行数 尽量少运算 尽量避免全表扫描,如果可以,在过滤列建立索引 尽量避免在where子句对字段进行null判断 尽量避免在 ...
- 18.Mysql SQL优化
18.SQL优化18.1 优化SQL语句的一般步骤 18.1.1 通过show status命令了解各种SQL的执行频率show [session|global] status; -- 查看服务器状态 ...
- mysql sql优化及注意事项
sql优化分析 通过slow_log等方式可以捕获慢查询sql,然后就是减少其对io和cpu的使用(不合理的索引.不必要的数据访问和排序)当我们面对具体的sql时,首先查看其执行计划A.看其是否使用索 ...
- MySQL sql优化(摘抄自文档)
前言 有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧. 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础. 优化目标 ...
- MySQL SQL优化
一.优化数据库的一般步骤: (A) 通过 show status 命令了解各种SQL的执行频率. (B) 定位执行效率较低的SQL语句,方法两种: 事后查询定位:慢查询日志:--log-slow-qu ...
- Mysql SQL 优化
1. 查询缓存 多数MySQL服务器都开启了查询缓存,相同的查询被执行多次,查询结果会被放到一个缓存中,这样,后续的相同的查询就不用操作表而直接访问缓存结果了. // 查询缓存不开启 $r = mys ...
- MySQL SQL优化之in与range查询【转】
本文来自:http://myrock.github.io/ 首先我们来说下in()这种方式的查询.在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效 ...
- MySql Sql 优化技巧分享
有天发现一个带inner join的sql 执行速度虽然不是很慢(0.1-0.2),但是没有达到理想速度.两个表关联,且关联的字段都是主键,查询的字段是唯一索引. sql如下: SELECT p_it ...
随机推荐
- B/S和C/S的区别。
现在软件开发的整体架构主要分为B/S架构与C/S架构 一,C/S——Client/Service:客户机/服务器模式: C/S (Client/Server)结构,即大家熟知的客户机和服务器结构.它是 ...
- Python之迭代器&装饰器&生成器&正则
1.迭代器 迭代器是访问数据集合的一种方式,它只能从集合的第一个元素开始顺序访问,直到最后一个元素结束.类似于linux里的cat命令,只能挨行读取文本内容,不可以跳到中间或者尾部读取(不会把所有的数 ...
- 好友与组--ESFramework 4.0 进阶(11)
大部分分布式通信系统中,都会涉及到客户端之间相互通信.以及需要将客户端进行分组的功能,或者是类似这方面的需求.ESFramework对这一常见的任务内置了强大的支持,包括从客户端到服务端.一直到Pla ...
- 使用紧凑的序列化器,数倍提升性能 —— ESFramework 4.0 快速上手(11)
在分布式通信系统中,网络传递的是二进制流,而内存中是我们基于对象模型构建的各种各样的对象,当我们需要将一个对象通过网络传递给另一个节点时,首先需要将其序列化为字节流,然后通过网络发送给目标节点,目标节 ...
- 【笔记】Loadrunner添加OS类型为Windows的服务器(Win7)
最近在学习Loadrunner,看到“监控Windows资源”,决定小试一把,由于没有找到合适的镜像,暂时没有搞好Windows的虚拟机,so 先用自己小试牛刀了只有,不过这样子好像难度锐减也~只要小 ...
- 请问如何查询一个APP的Android和iOS下载量?
作者:Jasmine Jiang链接:http://www.zhihu.com/question/28533067/answer/87871598来源:知乎著作权归作者所有,转载请联系作者获得授权. ...
- MySQL-MHA高可用方案
http://files.cnblogs.com/jimingsong/mha-mysql.pdf 此方案为一号店MySQL MHA高可用方案.备注.
- Objective-C和Swift实现单例的几种方式
在Swift开发中,我们对于跨类调用的变量常量,因为并没有OC中使用的全局头文件中写宏的形式,我们一般采用在类外定义全局变量/常量的形式来跨类调用.而问题在于目前写的项目需要在新添加的OC写的功能模块 ...
- mongoDB5--mongoDB增删改查
之前我们探讨了mongodb的"增删改查",要知道,我们的增删改其实都离不开查询表达式,所以查询表达式在mongodb是非常重要的.关于查询其实我们只是介绍了以小部分.关于mong ...
- jquety选择器
基本选择器 1.#id 根据id的属性值来获取元素 2.TagName 根据标签名来获取元素 3.selector1,selector2 匹配列表中的选择器(就是可以匹配多 ...