1.需要优化的sql

最近做一个基于.net mvc和MySQL的仓储系统的优化工作,遇到了一个执行特别慢的SQL语句,经过一番折腾,终于搞定啦,分享一下过程。问题就是下面这个家伙:

create or replace view view_task_meter_info
as
select t1.TASK_ID,t1.task_no,t1.BINDBOX_BARCODE as box_barcode,t1.EQUIP_BAR_CODE,t1.METER_STATUS,t1.ENTITY_TYPE as RSLT_CODE,
-- 设备类别
(SELECT name from data_dictionary_info t01 where t01.domain ='设备类别' and t01.code = t3.EQUIP_CATEG) as T_Equip_categ,
-- 类别
(select name from data_dictionary_info t09 where t09.domain = '类型' and t09.code = t3.TYPE_CODE) as
T_TYPE_CODE,
-- 类型
(select name from data_dictionary_info t09 where t09.domain = '类别' and t09.code = t3.RATED_CURRENT) as T_SORT_CODE,
t3.EQUIP_CATEG,t3.TYPE_CODE,t3.SORT_CODE
from
data_task_asset t1 left join data_meter_info t3 on t1.EQUIP_BAR_CODE=t3.BAR_CODE
union all
select t1.CHK_TASK_ID as task_id,t1.TASK_NO,t1.BOX_BARCODE,t1.BAR_CODE as Equip_bar_code,'00' as METER_STATUS,t1.RSLT_CODE,
-- 设备类别
(SELECT name from data_dictionary_info t01 where t01.domain ='设备类别' and t01.code = t3.EQUIP_CATEG) as T_Equip_categ,
-- 类别
(select name from data_dictionary_info t09 where t09.domain = '类型' and t09.code = t3.TYPE_CODE) as
T_TYPE_CODE,
-- 类型
(select name from data_dictionary_info t09 where t09.domain = '类别' and t09.code = t3.RATED_CURRENT) as T_SORT_CODE,
t3.EQUIP_CATEG,t3.TYPE_CODE,t3.SORT_CODE
from data_check_asset_info t1
LEFT JOIN data_meter_info t3 on t1.BAR_CODE = t3.BAR_CODE

解释一下业务:

仓储系统业务分为三块:出入库、盘点。data_task_asset是出入库任务资产明细,data_check_asset_info是盘点任务明细,data_meter_info是资产档案表。data_task_asset和data_check_asset_info表都使用资产条码(EQUIP_BAR_CODE/BAR_CODE)和资产档案表关联(BAR_CODE是档案表主键)。这个视图的业务意义就是展示出入库、盘点任务的资产明细(包括档案信息),同时需要把档案信息里面的大量代码字段翻译成文字信息。上面视图中只列出3个字段作为示例,实际上需要翻译的字段有十几个。

这个视图刚开始没有感觉慢,但是有一天测试做了一个7万多条明细的盘点任务后,每次查询一个任务的明细都要等上十几到几十秒,是在难以忍受。开工吧,先诊断一下。

2.查看执行情况

下面是这个视图在查询那个7万多条明细的盘点任务的执行时间,太可怕了,三十多秒。

看看执行计划

额滴神呀,这可肯定不行呀,每个字段的翻译都要查询字典表的1207条记录,一个记录需要翻译10次,7万条记录,需要查询字典表70万次,每次搜索记录1000多条,这个当然不行啦。

3.在字典表上加索引!!!

根据查询字典表的sql语句,我们在domain和code上加联合索引

SELECT name from data_dictionary_info t01 where t01.domain ='设备类别' and t01.code = t3.EQUIP_CATEG

来看现在的执行情况

执行时间:

执行时间一下子降到了两三秒,效果显著呀!

执行计划:

看看执行计划你也许就不吃惊啦,建立索引后每次查询字典表,只搜索一条记录。

4.再加两个索引

既然索引这么厉害,那就继续加索引呗,可以看到视图在查询出入库和盘点任务明细表时,也是全表查询。我们加个索引看看效果如何,我分别在data_task_asset的task_id和task_no、data_check_asset_info的chk_task_id和task_no上添加了联合索引。下面看看执行情况:

执行时间:

执行时间好像比刚才还长了一点,这就不合心意啦。

执行计划:

从执行计划来看,查询根本就没有用到索引,why?

5.mysql视图算法及不使用索引的情况

普及一些百度知识:

当用户创建视图时,mysql默认使用一种undefine的处理算法,就是会自动在合并和临时表内进行选择

  • 对于MERGE,会将引用视图的语句的文本与视图定义合并起来,使得视图定义的某一部分取代语句的对应部分。

  • 对于TEMPTABLE,视图的结果将被置于临时表中,然后使用它执行语句。

  • 对于UNDEFINED,MySQL将选择所要使用的算法。如果可能,它倾向于MERGE而不是TEMPTABLE,这是因为MERGE通常更有效,而且如果使用了临时表,视图是不可更新。

对于使用MERGE算法处理的视图,可以使用索引。但是,对于使用临时表算法处理的视图,不能在其基表上利用索引提供的优点。MERGE算法要求视图中的行和基表中的行具有一对一的关系。如果不具有该关系。必须使用临时表取而代之。如果视图包含下述结构中的任何一种,将失去一对一的关系:

  • 聚合函数(SUM(),MIN(),MAX(),COUNT()等)
  • DISTINCT
  • GROUP BY
  • HAVING
  • UNION或UNION ALL

通常的不使用索引的查询

  • 如果MySQL估计使用索引比全表扫描更慢,则不使用索引。例如,如果列key均匀分布在1和100之间,下面的查询使用索引就不是很好:select * from table_name where key>1 and key<90;

  • 如果使用MEMORY/HEAP表,并且where条件中不使用“=”进行索引列,那么不会用到索引,head表只有在“=”的条件下才会使用索引

  • 用or分隔开的条件,如果or前的条件中的列有索引,而后面的列没有索引,那么涉及到的索引都不会被用到,例如:select * from table_name where key1='a' or key2='b';如果在key1上有索引而在key2上没有索引,则该查询也不会走索引

  • 复合索引,如果索引列不是复合索引的第一部分,则不使用索引(即不符合最左前缀),例如,复合索引为(key1,key2),则查询select * from table_name where key2='b';将不会使用索引

  • 如果like是以‘%’开始的,则该列上的索引不会被使用。例如select * from table_name where key1 like '%a';该查询即使key1上存在索引,也不会被使用

  • 如果列为字符串,则where条件中必须将字符常量值加引号,否则即使该列上存在索引,也不会被使用。例如,select * from table_name where key1=1;如果key1列保存的是字符串,即使key1上有索引,也不会被使用。

6.干掉union all

为了证明确实是union all影响了索引的使用,我们去掉视图中的union all,让视图只负责查询盘点任务的明细及档案信息,看看效果如何。

-执行时间:

时间又比刚才短了一秒钟,不错,不错。

-执行计划

从执行计划可以看出,这次用到了明细表的索引。

7.存储过程使用

我们看到取到union all之后,明细表的索引在查询中被使用。尽管我们从查询的时间上感觉明细表使用索引和不使用索引没有太大差别。但这其实只是数据太少反映不出问题,随着明细表数据的增多,有索引时每个任务搜索的记录数只与明细数量有关;而无索引时,每个任务明细查询是全表搜索。所以,union all必须去掉。

那么问题来啦,程序结构已经基本定型,单个视图必须使用union all。这里有两种方案:

  • 分开为两个视图,出入库明细一个视图,盘点明细一个视图,在程序中控制使用不同视图;
  • 使用存储过程,在存储过程中判断查询出入库明细还是盘点明细。

在Entity Framework中使用存储过程还没尝试过,就用存储过程啦:

mysql存储过程代码:

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_task_meter_info`(IN `taskId` DECIMAL(16,0), IN `taskNo` VARCHAR(32), IN `ioFlag` VARCHAR(8))
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
if ioFlag = '盘点' then
-- 返回盘点明细
select * from ...
where ...
else
-- 返回出入库明细
select * from ...
where ...
end if;
END

Entity Framework调用存储过程(看上去也挺方便的):

var dataListProc =
DbContext.Database.SqlQuery<view_task_meter_info>(
string.Format("CALL `sp_task_meter_info`({0}, '{1}','{2}')",searchModel.task_id,searchModel.task_no,searchModel.task_type)).ToList();

8.疑问

  • 总感觉自己的翻译代码字段有点太费时,不知各位园友是怎么处理这种问题的。

好了,就到这里啦。这篇博客其实早该发出来的,因为一些耽搁,今天总算赶出来啦。我感觉每次要写一篇博客前,总感觉有好多东西要说,可是很多时候赶紧文章都写不流畅啦。动不动就想分条陈述,动不动就想来个问题原因,解决方案。而且一旦不能集中时间写完,再回首已是食之无味。成了个整天宥在自己项目、任务圈里的程序猿啦。这不行!

一个MySQL视图的优化过程的更多相关文章

  1. 【夯实Mysql基础】记一次mysql语句的优化过程

    1. [事件起因] 今天在做项目的时候,发现提供给客户端的接口时间很慢,达到了2秒多,我第一时间,抓了接口,看了运行的sql,发现就是 2个sql慢,分别占了1秒多. 一个sql是 链接了5个表同时使 ...

  2. 【夯实Mysql基础】记一次mysql语句的优化过程!

      1. [事件起因] 今天在做项目的时候,发现提供给客户端的接口时间很慢,达到了2秒多,我第一时间,抓了接口,看了运行的sql,发现就是 2个sql慢,分别占了1秒多. 一个sql是 链接了5个表同 ...

  3. MySQL 数据库性能优化之缓存参数优化

    在平时被问及最多的问题就是关于 MySQL 数据库性能优化方面的问题,所以最近打算写一个MySQL数据库性能优化方面的系列文章,希望对初中级 MySQL DBA 以及其他对 MySQL 性能优化感兴趣 ...

  4. MySQL查询语句执行过程及性能优化(JOIN/ORDER BY)-图

    http://blog.csdn.net/iefreer/article/details/12622097 MySQL查询语句执行过程及性能优化-查询过程及优化方法(JOIN/ORDER BY) 标签 ...

  5. MySQL查询语句执行过程及性能优化-查询过程及优化方法(JOIN/ORDER BY)

    在上一篇文章MySQL查询语句执行过程及性能优化-基本概念和EXPLAIN语句简介中介绍了EXPLAIN语句,并举了一个慢查询例子:

  6. 一次MySQL两千万数据大表的优化过程,三种解决方案

    问题概述 使用阿里云rds for MySQL数据库(就是MySQL5.6版本),有个用户上网记录表6个月的数据量近2000万,保留最近一年的数据量达到4000万,查询速度极慢,日常卡死.严重影响业务 ...

  7. MySQL查询语句执行过程及性能优化-基本概念和EXPLAIN语句简介

    网站或服务的性能关键点很大程度在于数据库的设计(假设你选择了合适的语言开发框架)以及如何查询数据上. 我们知道MySQL的性能优化方法,一般有建立索引.规避复杂联合查询.设置冗余字段.建立中间表.查询 ...

  8. 一个扩展搜索API的优化过程

    概述 API 是一个服务的门面,就像衣装是人的形象一样. 优雅的 API 设计,能让业务方使用起来倍儿爽,提升开发效率,降低维护成本:糟糕的 API 设计,则让业务方遭心,陷入混沌. 本文将展示一个扩 ...

  9. Mysql原理与优化

    原文:https://mp.weixin.qq.com/s__biz=MzI4NTA1MDEwNg==&mid=2650763421&idx=1&sn=2515421f09c1 ...

随机推荐

  1. Spring Cloud,Dubbo及HSF对比

    Round 1:背景 Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点.阿里巴巴近几年对开源社区的贡献不论在国内还是国外都是引人注目的,比如:JStorm捐赠给Apa ...

  2. 阿里面试100%问到,JVM性能调优篇

    JVM 调优概述 性能定义 吞吐量 - 指不考虑 GC 引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标. 延迟 - 其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收集 ...

  3. [Swift]LeetCode85. 最大矩形 | Maximal Rectangle

    Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and ...

  4. [Swift]LeetCode367. 有效的完全平方数 | Valid Perfect Square

    Given a positive integer num, write a function which returns True if num is a perfect square else Fa ...

  5. [Swift]LeetCode633. 平方数之和 | Sum of Square Numbers

    Given a non-negative integer c, your task is to decide whether there're two integers a and b such th ...

  6. [Swift]LeetCode952. 按公因数计算最大组件大小 | Largest Component Size by Common Factor

    Given a non-empty array of unique positive integers A, consider the following graph: There are A.len ...

  7. 写给需要的Javaer-大数据学习路线篇

    已经更新100+篇~ 关注公众号,BAT大神带你飞~ 听说你还在写Java,看Spring,看Dubbo,今天SpringCloud, 明天Dubbo3.X新版本... 10个开发9个半在写Java后 ...

  8. Python 字典和集合基于哈希表实现

    哈希表作为基础数据结构我不多说,有兴趣的可以百度,或者等我出一篇博客来细谈哈希表.我这里就简单讲讲:哈希表不过就是一个定长数组,元素找位置,遇到哈希冲突则利用 hash 算法解决找另一个位置,如果数组 ...

  9. 9.Flask Cookie和Session

    1.1.概念 cookie:在网站中,http请求是无状态的.也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户.cookie的出现就是为了解决这个问题,第 ...

  10. cmd命令窗口的快速选中复制黏贴

    右击"窗口标题栏",选择属性,进入属性面板: 在"选项"面板勾选编辑选项下的"快速编辑模式"; 点击确认. 这时鼠标左键就有了选中功能,可以 ...