一个MySQL视图的优化过程

时间:2022-08-24 08:45:09

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万多条明细的盘点任务的执行时间,太可怕了,三十多秒。

一个MySQL视图的优化过程

看看执行计划

一个MySQL视图的优化过程

额滴神呀,这可肯定不行呀,每个字段的翻译都要查询字典表的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

一个MySQL视图的优化过程

来看现在的执行情况

执行时间:

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

一个MySQL视图的优化过程

执行计划:

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

一个MySQL视图的优化过程

4.再加两个索引

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

执行时间:

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

一个MySQL视图的优化过程

执行计划:

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

一个MySQL视图的优化过程

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,让视图只负责查询盘点任务的明细及档案信息,看看效果如何。

-执行时间:

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

一个MySQL视图的优化过程

-执行计划

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

一个MySQL视图的优化过程

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&sol;ORDER BY&rpar;-图

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

  5. MySQL查询语句执行过程及性能优化-查询过程及优化方法(JOIN&sol;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. &lbrack;转&rsqb; 评 WOW技能天赋设计

    本文转至:http://bbs.chinaunix.net/thread-1692302-8-1.html(只作转载, 不代表本站和博主同意文中观点或证实文中信息)再比如,传说中的面向对象本该大显神威 ...

  2. 最实用的IT类网站及工具大集合

    1.聚合数据 大家在开发过程中,可能会用到各种各样的数据,想找一些接口来提供一些数据.比如天气预报查询,火车时刻表查询,彩票查询,身份证查询等等.有了这个接口,直接调用即可.各种各样的API接口满足你 ...

  3. spring boot分布式技术,spring cloud,负载均衡,配置管理器

    spring boot分布式的实现,使用spring cloud技术. 下边是我理解的spring cloud的核心技术: 1.配置服务器 2.注册发现服务器eureka(spring boot默认使 ...

  4. Extjs TabPanel 选项卡延迟加载

    Extjs TabPanel 选项卡延迟加载 说明: Ext中用到tabpanel选项卡控件, 选项卡页签默认是延迟加载的, 当用户手工切换到某页签下时该页签才会加载, 在页签没有加载前, 用户对该页 ...

  5. git不能提交jar的设置

      项目目录下 文件:.gitignore ,里面设置: *.class # Package Files # *.jar *.war *.ear 删除*.jar

  6. 一些技术blog和安全blog

    1.安全blog: http://zenxds.com/blog/ http://navisec.it/ http://huaidan.org/ http://leapar.lofter.com/ h ...

  7. js编码、解码

    js对文字进行编码涉及3个函数:escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decodeURIComponent 1 ...

  8. 四、I&sol;O

    九.什么是I/O: 9.1.在Windows程序中,基础的运行单位为线程,为每一个线程分配一个处理器,可以让系统执行多个操作, 9.2.当线程进行一个I/O操作时,会被挂起,从而影响性能,为了解决这类 ...

  9. ios WKWebView 与 JS 交互实战技巧

    一.WKWebView 由于Xcode8发布之后,编译器开始不支持iOS 7了,这样我们的app也改为最低支持iOS 8.0,既然需要与web交互,那自然也就选择使用了 iOS 8.0之后 才推出的新 ...

  10. Apache kylin 入门

    本篇文章就概念.工作机制.数据备份.优势与不足4个方面详细介绍了Apache Kylin. Apache Kylin 简介 1. Apache kylin 是一个开源的海量数据分布式预处理引擎.它通过 ...