数据准备:

-- 创建数据库
mysql> create database db_index_case;
Query OK, 1 row affected (0.00 sec) -- 查看数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db02 |
| db_index |
| db_index_case |
| db_test |
| mysql |
| performance_schema |
| test |
+--------------------+
8 rows in set (0.01 sec)

导入表数据结构:

/*
Navicat MySQL Data Transfer Source Server : localhost_3306
Source Server Version : 50203
Source Host : localhost:3306
Source Database : db_test Target Server Type : MYSQL
Target Server Version : 50203
File Encoding : 65001 Date: 2017-06-29 09:19:23
*/ SET FOREIGN_KEY_CHECKS=0; -- ----------------------------
-- Table structure for tb_emp
-- ----------------------------
DROP TABLE IF EXISTS `tb_emp`;
CREATE TABLE `tb_emp` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(20) NOT NULL COMMENT '姓名',
`sex` char(1) NOT NULL COMMENT '性别',
`age` int(11) NOT NULL COMMENT '年龄',
`jobLen` int(11) NOT NULL COMMENT '工作年限',
PRIMARY KEY (`id`),
KEY `idx_emp_sja` (`sex`,`jobLen`,`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of tb_emp
-- ----------------------------
INSERT INTO `tb_emp` VALUES ('', '张三', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '李四', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '王二', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '麻子', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小花', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小明', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小四', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小李', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小丹', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小花', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小冷', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小邳', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小影', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小兰', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小翟', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '大花', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '大胖', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '小胖', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '骚欣', '', '', '');
INSERT INTO `tb_emp` VALUES ('', '雷子', '', '', '');

业务要求:查找性别为男性(0:女,1:男),工作年限大于3年,年龄最小的员工。

mysql> select * from tb_emp where sex = '' and jobLen > 3 order by age limit 1;
+----+--------+-----+-----+--------+
| id | name | sex | age | jobLen |
+----+--------+-----+-----+--------+
| 11 | 小冷 | 1 | 24 | 5 |
+----+--------+-----+-----+--------+
1 row in set (0.00 sec)

查看执行计划:

mysql> explain select * from tb_emp where sex = '' and jobLen > 3 order by age limit 1;
+----+-------------+--------+------+---------------+------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | tb_emp | ALL | NULL | NULL | NULL | NULL | 20 | Using where; Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+------+-----------------------------+
1 row in set (0.00 sec)

结论:type为ALL,即最坏的情况;key为null,没有用到索引;Extra中含有Using filesort,不是按照表内的索引进行排序。

优化开始:

  •  创建索引:
  • mysql> create index idx_emp_sex_jobLen_age on tb_emp(sex, jobLen, age);
    Query OK, 0 rows affected (1.59 sec)
    Records: 0 Duplicates: 0 Warnings: 0 -- 查看索引
    mysql> show index from tb_emp;
    +--------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +--------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | tb_emp | 0 | PRIMARY | 1 | id | A | 20 | NULL | NULL | | BTREE | | |
    | tb_emp | 1 | idx_emp_sex_jobLen_age | 1 | sex | A | 4 | NULL | NULL | | BTREE | | |
    | tb_emp | 1 | idx_emp_sex_jobLen_age | 2 | jobLen | A | 20 | NULL | NULL | | BTREE | | |
    | tb_emp | 1 | idx_emp_sex_jobLen_age | 3 | age | A | 20 | NULL | NULL | | BTREE | | |
    +--------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    4 rows in set (0.00 sec)
  •  查看执行计划:
  • mysql> explain select * from tb_emp where sex = '' and jobLen > 3 order by age limit 1;
    +----+-------------+--------+------+------------------------+------------------------+---------+-------+------+----------------------------------------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+------------------------+------------------------+---------+-------+------+----------------------------------------------------+
    | 1 | SIMPLE | tb_emp | ref | idx_emp_sex_jobLen_age | idx_emp_sex_jobLen_age | 3 | const | 8 | Using index condition; Using where; Using filesort |
    +----+-------------+--------+------+------------------------+------------------------+---------+-------+------+----------------------------------------------------+
    1 row in set (0.00 sec) -- 将 jobLen > 3 改变成 jobLen = 3 比较两个查询执行计划
    mysql> explain select * from tb_emp where sex = '' and jobLen = 3 order by age limit 1;
    +----+-------------+--------+------+------------------------+------------------------+---------+-------------+------+------------------------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+------------------------+------------------------+---------+-------------+------+------------------------------------+
    | 1 | SIMPLE | tb_emp | ref | idx_emp_sex_jobLen_age | idx_emp_sex_jobLen_age | 7 | const,const | 5 | Using index condition; Using where |
    +----+-------------+--------+------+------------------------+------------------------+---------+-------------+------+------------------------------------+
    1 row in set (0.00 sec)

   结果:Extra 中还是存在 Using filesort。

   分析:比对改变jobLen > 3 条件前后的查询执行计划,可以得出是因为 jobLen > 3 导致索引失效。因为按照 BTree 索引的工作原理,首先排序 sex,若是遇到相同的 sex 则再去排序 jobLen,若是遇到相同的 jobLen 则再去排序 age。按照联合索引顺序向下去排序,可是 where 后查询条件 jobLen > 3  是一个范围值( range ),导致索引失效,MySQL 无法对后面的 age 进行检索,即 range 类型查询字段后面的索引失效。

  • 删除索引,重新创建:
  • -- 删除索引
    mysql> drop index idx_emp_sex_jobLen_age on tb_emp;
    Query OK, 0 rows affected (0.02 sec)
    Records: 0 Duplicates: 0 Warnings: 0 -- 创建索引
    mysql> create index idx_emp_sex_age on tb_emp(sex, age);
    Query OK, 0 rows affected (1.60 sec)
    Records: 0 Duplicates: 0 Warnings: 0 -- 查看索引
    mysql> show index from tb_emp;
    +--------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +--------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | tb_emp | 0 | PRIMARY | 1 | id | A | 20 | NULL | NULL | | BTREE | | |
    | tb_emp | 1 | idx_emp_sex_age | 1 | sex | A | 4 | NULL | NULL | | BTREE | | |
    | tb_emp | 1 | idx_emp_sex_age | 2 | age | A | 20 | NULL | NULL | | BTREE | | |
    +--------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    3 rows in set (0.00 sec)
  • 查询执行计划:
  • mysql> explain select * from tb_emp where sex = '' and jobLen > 3 order by age limit 1;
    +----+-------------+--------+------+-----------------+-----------------+---------+-------+------+------------------------------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    +----+-------------+--------+------+-----------------+-----------------+---------+-------+------+------------------------------------+
    | 1 | SIMPLE | tb_emp | ref | idx_emp_sex_age | idx_emp_sex_age | 3 | const | 13 | Using index condition; Using where |
    +----+-------------+--------+------+-----------------+-----------------+---------+-------+------+------------------------------------+
    1 row in set (0.00 sec)

   结果:Extra 中的 Using filesort 优化之后消失了,完成任务。 

注意:

mysql> explain select * from tb_emp where sex = 1 and jobLen > 3 order by age limit 1;
+----+-------------+--------+------+-----------------+------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+-----------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | tb_emp | ALL | idx_emp_sex_age | NULL | NULL | NULL | 20 | Using where; Using filesort |
+----+-------------+--------+------+-----------------+------+---------+------+------+-----------------------------+
1 row in set (0.02 sec)

结果: type 为 ALL,key 为 NULL,rows 为 20,Extra 中包含 Using filesort。

查看表结构:

-- 查看表结构
mysql> desc tb_emp;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| sex | char(1) | NO | MUL | NULL | |
| age | int(11) | NO | | NULL | |
| jobLen | int(11) | NO | | NULL | |
+--------+-------------+------+-----+---------+----------------+
5 rows in set (0.02 sec)

分析:因为 sex 为 char 类型的字段, sql 查询条件中 sex = 1 是数字类型。因为类型不匹配,MySQL 会自动解析字符类型,会浪费性能。

SQL优化单表案例的更多相关文章

  1. sql server单表导入、导出

    sql server单表导入.导出(通过CSV文件) 导出:直接打开查询分析器查询要导出表的信息(select *  from 表),得到的结果全选,右键另存为 xxx.csv文件  (得到该表的所有 ...

  2. 3.MySQL优化---单表查询优化的一些小总结(非索引设计)

    整理自互联网.摘要: 接下来这篇是查询优化.其实,大家都知道,查询部分是远远大于增删改的,所以查询优化会花更多篇幅去讲解.本篇会先讲单表查询优化(非索引设计).然后讲多表查询优化.索引优化设计以及库表 ...

  3. sql语句-单表查询

    一:单表查询 CREATE TABLE `Score`( `s_id` ), `c_id` ), `s_score` ), PRIMARY KEY(`s_id`,`c_id`) ); ); ); ); ...

  4. SQL Server单表已700w+将普通表转换成分区表

    最近项目中,某个表数据量爆发时增长,单表已700w+,读写性能急剧下降,所以考虑加入分区表以解燃眉之急,后续还是要分表分库,当然这是后话.下面简要说一下将普通表转为分区表的步骤.   一.创建文件组 ...

  5. SQL Server单表已700w+将普通表转换成分区表1

    最近项目中,某个表数据量爆发时增长,单表已700w+,读写性能急剧下降,所以考虑加入分区表以解燃眉之急,后续还是要分表分库,当然这是后话.下面简要说一下将普通表转为分区表的步骤.   一.创建文件组 ...

  6. SQL之单表与多表查询

    DML语句使用 source  路径  :把SQL脚本导入到数据库中 查询语句类型:[简单查询|多表查询|子查询] 投影:select    字段名,字段名   from   表名   where   ...

  7. sql优化-派生表与inner-join

    首先来说明一下派生表? 外部的表查询的结果集是从子查询中生成的.如下形式: select ... from (select ....) dt 如上形式中括号中的查询的结果作为外面select语句的查询 ...

  8. 数据库——SQL数据单表查询

    数据查询   语句格式 SELECT [ALL|DISTINCT] <目标列表达式> [,<目标列表达式>] … FROM <表或视图名>[,<表或视图名&g ...

  9. Mysql优化单表查询

    借助explain分析SQL,判断该怎么建立索引. 还需要注意,有些情况会导致索引失效,用不上索引,应该优化SQL,应用上索引. 什么情况导致索引失效? 1.在索引列上做任何操作(计算.函数.类型转换 ...

随机推荐

  1. ABAP CDS - 字符串函数

    下表显示了ABAP CDS中CDS视图中字符串的潜在SQL函数,以及对参数的要求.函数的含义可以在字符串的SQL函数下找到. 函数 参数类型 返回类型 CONCAT(arg1, arg2) See b ...

  2. C 二维指针难点详解。

    关于   指向二维数组的指针. int  a[2][3]; int *p; int (*p_1)[3]; 可以用p_1 = a ,但是不能用p = a : 因为此时数组a的数据类型是  int (* ...

  3. 【转】Django添加静态文件设置

    STATIC_URL = '/statics/'STATIC_ROOT= os.path.join(BASE_DIR, 'statics')STATICFILES_DIRS = ( os.path.j ...

  4. P2347 砝码称重

    P2347 砝码称重 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入输出格式 输入格式: 输入方式:a1 a2 a3 a4 a5 a6 (表示1 ...

  5. P1991 无线通讯网

    P1991 无线通讯网 题目描述 国防部计划用无线网络连接若干个边防哨所.2 种不同的通讯技术用来搭建无线网络: 每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫 ...

  6. laravel+vue结合使用

        SegmentFault 首页 问答 专栏 讲堂 圈子 发现 搜索 立即登录免费注册 在 SegmentFault,学习技能.解决问题 每个月,我们帮助 1000 万的开发者解决各种各样的技术 ...

  7. Android系统自带样式

    android:theme="@android:style/Theme.Dialog" 将一个Activity显示为能话框模式  android:theme="@andr ...

  8. python,批量生成指定格式的审核数据(传输参数格式为数组时)

    #思路#获取list长度(例如列表有20条数据,则生成20条数据),生成数组长度为list元素的数据,完成对列表20条数据的批量审核def createBatchData(self,str_in,li ...

  9. Appium iOS万能的定位方式--Predicate(iOSNsPredicate)

    所谓Predicate定位即Java-Client -5.0.版本以及Appium-Python-Client 0.31版本更新后增加的新的定位方式: 举个例子: JAVA代码: //输入账号和密码 ...

  10. nginx启动和配置

    1.命令行参数 -c </path/to/config> 为 Nginx 指定一个配置文件,来代替缺省的.路径应为绝对路径 -t 不运行,而仅仅测试配置文件.nginx 将检查配置文件的语 ...