SQL优化目的:

降低响应时间
直接影响用户体验度

降低资源使用率
主要体现在IO和CPU上,网络、内存消耗

优化原则:

1.IN子查询改成JOIN
2.NOT IN子查询改成LEFT JOIN
3.消除无效子查询
4.禁用select *,只读取所需字段
5.LIMIT M, N 大分页修改成JOIN形式
6.大结果集 limit限制,where限制,分页读取
7.使用where xx IN (),IN子句中元素建议小于200
8.多表Join时,注意比较字段类型一致,避免隐式类型转换
9.Where子句右值都用单引号括起,避免隐式类型转换
10.Update/delete根据索引删除,禁用Update/delete … limit N结构SQL
11.禁止对索引列进行数值计算

1.类型转化(避免隐式的类型转换)

mysql> desc tb_shop_order
-> ;
+----------------------+----------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+----------------+------+-----+---------------------+-----------------------------+
| id | varchar(60) | NO | PRI | NULL | |
| gorder_id | varchar(60) | NO | MUL | NULL | |
| product_type | char(4) | NO | MUL | NULL | |
| order_time | timestamp | NO | MUL | 0000-00-00 00:00:00 | |
| order_status | tinyint(2) | NO | MUL | NULL | |
| order_amount | decimal(12,2) | NO | | 0.00 | |
| save_amount | decimal(12,2) | NO | | 0.00 | |
| pay_amount | decimal(12,2) | NO | | 0.00 | |
| logistics_amount | decimal(12,2) | YES | | NULL | |
| fee | decimal(12,2) | NO | | 0.00 | |
| original_pay_amount | decimal(12,2) | NO | | 0.00 | |
| cost_amount | decimal(12,2) | NO | | 0.00 | |
| buy_account_id | varchar() | NO | MUL | NULL | |
| pre_close_time | timestamp | NO | MUL | 0000-00-00 00:00:00 | |
| update_time | timestamp | NO | MUL | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| settle_up | tinyint(1) | NO | MUL | NULL | |
| success_time | timestamp | NO | | 0000-00-00 00:00:00 | |
| merchant_id | int(10) | NO | MUL | NULL | |
| merchant_name | varchar(100) | NO | MUL | NULL | |
| merchant_account | varchar(100) | YES | | NULL | |
| merchant_tel | varchar(60) | YES | | NULL | |
| merchant_order_id | varchar(100) | YES | MUL | NULL | |
| merchant_amount | decimal(12,2) | YES | | NULL | |
| activity_id | int(10) | YES | | NULL | |
| activity_type | tinyint(2) | YES | | NULL | |
| order_desc | varchar(1000) | YES | | NULL | |
| remark | varchar(500) | YES | | NULL | |
| can_deliver | tinyint(1) | YES | | NULL | |
| can_settle_up | tinyint(1) | YES | | NULL | |
| can_refund | tinyint(1) | YES | | NULL | |
| misc | varchar(14100) | YES | | NULL | |
| key_words | varchar(200) | YES | | NULL | |
| delivery_begin_time | timestamp | NO | MUL | 0000-00-00 00:00:00 | |
| delivery_end_time | timestamp | NO | MUL | 0000-00-00 00:00:00 | |
| relation_id | varchar(60) | YES | | NULL | |
| order_ip | varchar(60) | YES | | NULL | |
| closed_reason | varchar(60) | YES | | NULL | |
| status_desc | varchar(60) | YES | | NULL | |
| note | varchar(5120) | YES | | NULL | |
| refund_amount | decimal(12,2) | NO | | 0.00 | |
| distributor_order_id | varchar(100) | NO | MUL | | |
+----------------------+----------------+------+-----+---------------------+-----------------------------+
41 rows in set (0.00 sec)

 定义: `buy_account_id` varchar(60) NOT NULL COMMENT '卡号',

mysql> explain select * from tb_shop_order where buy_account_id = 190000000033703177;
+----+-------------+---------------+------------+------+--------------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+--------------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | tb_shop_order | NULL | ALL | ix_order_accountid | NULL | NULL | NULL | 179981 | 10.00 | Using where |
+----+-------------+---------------+------------+------+--------------------+------+---------+------+--------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)

改造之后:ref 走的是const,rows扫描的行数表少,不在是全表扫描了

mysql> explain select * from tb_shop_order where buy_account_id = '';
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | tb_shop_order | NULL | ref | ix_order_accountid | ix_order_accountid | 182 | const | 1418 | 100.00 | NULL |
+----+-------------+---------------+------------+------+--------------------+--------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

原则:Where子句右值都用单引号括起,避免隐式类型转换!!!

2.字段计算(使用函数在字段上,不走索引)

mysql> explain select * from tb_shop_order where DATE_FORMAT (order_time,'%Y-%m-%d') = '2016-04-05';
+----+-------------+---------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | tb_shop_order | NULL | ALL | NULL | NULL | NULL | NULL | 179981 | 100.00 | Using where |
+----+-------------+---------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

改造之后:row 扫描的行数变少,不再是全表烧苗,而是范围扫描,而且

Extra Using index

这是性能很高的一种情况。当查询所需的数据可以直接从索引树中检索到时,就会出现。

mysql> explain select * from tb_shop_order where order_time > '2016-04-05 00:00:00' and order_time < '2016-04-05 23:59:59';
+----+-------------+---------------+------------+-------+----------------+----------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+-------+----------------+----------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | tb_shop_order | NULL | range | ix_order_otime | ix_order_otime | 4 | NULL | 89 | 100.00 | Using index condition |
+----+-------------+---------------+------------+-------+----------------+----------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

3.避免全表扫描更新

(1) update XXX set batch = '2016-09-27 16:21:01'

where batch = '1970-01-01 08:00:30';

(2) delete from XXX where batch   <   '2016-09-26 16:21:00';

改造成根据主键批量更新:

select min(pk), max(pk) from table where batch = '1970-01-01 08:00:30';

Update … where batch = '1970-01-01 08:00:30' and pk >= min and pk < i
Update … where batch = '1970-01-01 08:00:30' and pk >= i and pk < j
Update … where batch = '1970-01-01 08:00:30' and pk >= j and pk < max

4.字段传值正确性

错误的拼接:

select * from tb_shop_order where order_time > CONCAT('2016-04-05 00:00:00','00:00:00') and order_time < CONCAT('2016-04-05 23:59:59','00:00:00');

select * from tb_shop_order where order_time > '2016-04-05 00:00:00' and order_time < '2016-04-05 23:59:59./';

5. in OR not in优化

mysql> explain select * from tb_shop_order where buy_account_id  ='' and product_type in (select product_type from tb_shop_gorder );
+----+-------------+----------------+------------+------+----------------------------------+--------------------+---------+-------------------------------+-------+----------+----------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------------+------------+------+----------------------------------+--------------------+---------+-------------------------------+-------+----------+----------------------------------------+
| 1 | SIMPLE | tb_shop_order | NULL | ref | ix_order_accountid,ix_order_prod | ix_order_accountid | 182 | const | 6 | 100.00 | NULL |
| 1 | SIMPLE | tb_shop_gorder | NULL | ref | ix_gorder_ptype | ix_gorder_ptype | 12 | lp.tb_shop_order.product_type | | 100.00 | Using index; FirstMatch(tb_shop_order) |
+----+-------------+----------------+------------+------+----------------------------------+--------------------+---------+-------------------------------+-------+----------+----------------------------------------+
2 rows in set, 1 warning (0.00 sec)

改造后:

mysql> explain select t1.* from tb_shop_order t1 INNER JOIN tb_shop_gorder t2 on t1.product_type = t2.product_type  where t1.buy_account_id  ='';
+----+-------------+-------+------------+------+----------------------------------+--------------------+---------+--------------------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+----------------------------------+--------------------+---------+--------------------+-------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | ref | ix_order_accountid,ix_order_prod | ix_order_accountid | 182 | const | 6 | 100.00 | NULL |
| 1 | SIMPLE | t2 | NULL | ref | ix_gorder_ptype | ix_gorder_ptype | 12 | lp.t1.product_type | 10333 | 100.00 | Using index |
+----+-------------+-------+------------+------+----------------------------------+--------------------+---------+--------------------+-------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
mysql> explain select * from tb_shop_order where buy_account_id  ='' and product_type not in (select product_type from tb_shop_gorder );+----+--------------------+----------------+------------+----------------+--------------------+--------------------+---------+-------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+----------------+------------+----------------+--------------------+--------------------+---------+-------+-------+----------+-------------+
| 1 | PRIMARY | tb_shop_order | NULL | ref | ix_order_accountid | ix_order_accountid | 182 | const | 6 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | tb_shop_gorder | NULL | index_subquery | ix_gorder_ptype | ix_gorder_ptype | 12 | func | 10333 | 100.00 | Using index |
+----+--------------------+----------------+------------+----------------+--------------------+--------------------+---------+-------+-------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

改造后:

mysql> explain select t1.* from tb_shop_order t1 LEFT  JOIN tb_shop_gorder t2 on t1.product_type = t2.product_type  where t1.buy_account_id  ='' and t2.product_type IS NULL;
+----+-------------+-------+------------+------+--------------------+--------------------+---------+--------------------+-------+----------+--------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+--------------------+--------------------+---------+--------------------+-------+----------+--------------------------------------+
| 1 | SIMPLE | t1 | NULL | ref | ix_order_accountid | ix_order_accountid | 182 | const | 6 | 100.00 | NULL |
| 1 | SIMPLE | t2 | NULL | ref | ix_gorder_ptype | ix_gorder_ptype | 12 | lp.t1.product_type | 10333 | 100.00 | Using where; Not exists; Using index |
+----+-------------+-------+------------+------+--------------------+--------------------+---------+--------------------+-------+----------+--------------------------------------+
2 rows in set, 1 warning (0.00 sec)

mysql优化总结的更多相关文章

  1. MySQL优化聊两句

    原文地址:http://www.cnblogs.com/verrion/p/mysql_optimised.html MySQL优化聊两句 MySQL不多介绍,今天聊两句该如何优化以及从哪些方面入手, ...

  2. 0104探究MySQL优化器对索引和JOIN顺序的选择

    转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...

  3. mysql 优化

    1.存储过程造数据 CREATE DEFINER=`root`@`localhost` PROCEDURE `generate_test_data`(`n` int) begin declare i ...

  4. mysql优化笔记之分页

    过年闲得蛋疼,于是看看mysql优化,看了网上好多关于分页的优化方法,但是呢,我亲自试上一把的时候,没有出现他们说的现象...难道是我的机器问题么? 下面看看我的实践记录,希望看到的加入进来交流一下O ...

  5. MySQL优化概述

    一. MySQL优化要点 MySQL优化是一门复杂的综合性技术,主要包括: 1 表的设计合理化(符合 3NF,必要时允许数据冗余) 2.1 SQL语句优化(以查询为主) 2.2 适当添加索引(主键索引 ...

  6. MySQL优化实例

    这周就要从泰笛离职了,在公司内部的wiki上,根据公司实际的项目,写了一些mysql的优化方法,供小组里的小伙伴参考下,没想到大家的热情很高,还专门搞了个ppt讲解了一下. 举了三个大家很容易犯错的地 ...

  7. Mysql优化系列(2)--通用化操作梳理

    前面有两篇文章详细介绍了mysql优化举措:Mysql优化系列(0)--总结性梳理Mysql优化系列(1)--Innodb引擎下mysql自身配置优化 下面分类罗列下Mysql性能优化的一些技巧,熟练 ...

  8. mysql优化记录

    老板反应项目的反应越来越慢,叫优化一下,顺便学习总结一下mysql优化. 不同引擎的优化,myisam读的效果好,写的效率差,使用场景 非事务型应用只读类应用空间类应用 Innodb的特性,innod ...

  9. mysql 优化实例之索引创建

    mysql 优化实例之索引创建 优化前: pt-query-degist分析结果: # Query 23: 0.00 QPS, 0.00x concurrency, ID 0x78761E301CC7 ...

  10. MySQL优化的奇技淫巧之STRAIGHT_JOIN

    原文地址:http://huoding.com/2013/06/04/261 问题 通过「SHOW FULL PROCESSLIST」语句很容易就能查到问题SQL,如下: SELECT post.* ...

随机推荐

  1. 单步调试 step into/step out/step over 区别

    step into:单步执行,遇到子函数就进入并且继续单步执行(简而言之,进入子函数): step over:在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止, ...

  2. vc++ 6.0下Glut的配置 及 Glut 框架介绍

    2014-04-08  16:18:30 一.配置Glut 学习来源: http://blog.sina.com.cn/s/blog_5f0cf7bd0100c9oa.html 亲测可行. Glut的 ...

  3. 让scrollView、tableView滚动到底部

    - (void)scrollsToBottomAnimated:(BOOL)animated { CGFloat offset = self.tableView.contentSize.height ...

  4. C/C++中的getline函数总结:

    来自:http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html C/C++中的getline函数总结 getline函数是一个比较 ...

  5. ubuntu查看版本命令

    有两种方法 1,cat /etc/issue 2,sudo lsb_release -a 这个查询出来的结果比上面的那个全一些.

  6. 百科编辑器ueditor应用笔记

    最近项目上要用到文本编辑器,选了百科开源的ueditor,使用过程中虽然有些问题,但是一个个都解决了,记录如下: 开发的项目环境是vs2012:.net4.0: 1:百度js编辑器,编辑器加载到项目中 ...

  7. Jquery validate插件使用方法详解

    html: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Reg.aspx.c ...

  8. userdate和table类型的效率对比

    做cocos2d-x开发的人可能有不少人在实现类时会利用cocos2d-x自己给出的类的实现,也即在luaBinding目录下extern.lua的文件中给出的实现: --Create an clas ...

  9. 分页控件-ASP.NET(AspNetPager)

    AspNetPager是asp.net中常用的分页控件,下载AspNetPager.dll,添加引用,在工具栏就可以看到AspNetPager控件: <div class="oa-el ...

  10. 解决Yum安装依赖问题

    导读 最近在网上看到很多关于安装网络Yum源是报错的求助,本小白也曾遇到过此类问题,后找过度娘没有有效的解决办法.最后,经过几番尝试后终于解决,现在将解决方案共享给大家! Yum源及安装 安装过程在之 ...