一、索引设置

1、索引的设置原则

经常出现在WHERE条件、关联条件中的字段作为索引字段;

在满足查询需求的前提下,应尽可能少的创建索引;(对于一个组合索引,可以满足以组合索引左边的一部分字段的查询需求);

经常更新的字段,不适合创建索引;

区分度太低的字段,不适合创建索引;

不要为永远不会出现在WHERE条件、关联条件中的字段创建索引;

2、案例分析

比如有下面一张表:

查询需求如下:

需求一:按单个客户编号查询某个客户的交易明细。

需求二:按单个客户编号查询某个时间段的某只股票的交易明细。

需求三:统计某个时间段每只股票不同交易类型的交易金额。

需求四:统计每天所有股票的交易金额。

需求五:统计每只股票所有的交易费用。

查询一:SELECT * FROM stock_trans_detail WHERE customer_id = '?';

查询二:SELECT * FROM stock_trans_detail WHERE customer_id = '?' AND trans_date BETWEEN '2020-01-01' AND '2020-12-31' AND stock_code = '?';

查询三:SELECT stock_code,trans_type,sum(price*volume) FROM stock_trans_detail WHERE trans_date BETWEEN '2020-01-01' AND '2020-12-31' GROUP BY stock_code,trans_type;

查询四:SELECT trans_date,sum(price*volume) FROM stock_trans_detail GROUP BY trans_date;

查询五:SELECT stock_code,sum(fee) FROM stock_trans_detail GROUP BY stock_code;

索引设置分析:

需求一:按单个客户编号查询某个客户的交易明细。
需求二:按单个客户编号查询某个时间段的某只股票的交易明细。
需求三:统计某个时间段每只股票不同交易类型的交易金额。
需求四:统计每天所有股票的交易金额。
需求五:统计每只股票所有的交易费用。 索引一:customer_id
索引二:customer_id,trans_date,stock_code
索引三:trans_date,stock_code
索引四:无
索引五:无 最终:
索引一:customer_id,trans_date,stock_code
索引二:trans_date,stock_code

二、SQL优化

1、SQL优化的五个层次

主键 –> 唯一索引 –> 非唯一索引 –> 全表扫描(应尽量避免)

2、SQL优化的15条铁律

铁律1:尽量避免在索引列上使用表达式

如:
SELECT * FROM score WHERE score / 100 >= 0.6;
转换为:
SELECT * FROM score WHERE score >= 0.6 * 100; SELECT * FROM score WHERE LEFT(student_id,1) = 'S';
转换为:
SELECT * FROM score WHERE student_id LIKE 'S%';

铁律2:尽量避免在WHERE条件中使用NOT、<>和!=操作符

如:
SELECT * FROM score WHERE score <> 50;
转换为:
SELECT * FROM score WHERE score > 50 OR score < 50;

SELECT * FROM score WHERE score > 50;
UNION ALL
SELECT * FROM score WHERE score < 50;

铁律3:避免索引列的隐式类型转换

如:
SELECT * FROM stock_trans_detail WHERE stock_code = 600001;
转换为:
SELECT * FROM stock_trans_detail WHERE stock_code = '600001';

铁律4:在OR的两个条件上都有索引的话,将OR转换为UNION或UNION ALL

如:
SELECT * FROM score WHERE score = 100 OR gender = '男';
转换为:
SELECT * FROM score WHERE score = 100
UNION
SELECT * FROM score WHERE gender = '男';

铁律5:使用IN操作符替换OR

如:
SELECT * FROM score WHERE score = 100 OR score = 99;
转换为:
SELECT * FROM score WHERE score IN (100,99);

铁律6:使用BETWEEN操作符替换IN

如:
SELECT * FROM score WHERE score IN (100,99,98,97,96,95);
转换为:
SELECT * FROM score WHERE score BETWEEN 95 AND 100;

铁律7:在合适的情况下,使用EXISTS操作符替换IN

如:
SELECT * FROM stock
WHERE stock_code IN (
SELECT stock_code FROM stock_trans_detail
WHERE trans_date BETWEEN '2020-01-01' AND '2020-12-31'
);
转换为:
SELECT * FROM stock a
WHERE EXISTS (
SELECT 1 FROM stock_trans_detail b
WHERE a.stock_code = b.stock_code
AND b.trans_date BETWEEN '2020-01-01' AND '2020-12-31'
); 子查询结果集较大时,适合用EXISTS;
子查询结果集较小时,适合用IN;

铁律8:LIKE通配符也可能导致索引失效

如:
SELECT * FROM score WHERE subject_name LIKE '%机%';
转换为:
SELECT * FROM score WHERE subject_name LIKE '机%'
UNION ALL
SELECT * FROM score WHERE subject_name LIKE '计算机%';

SELECT * FROM score
WHERE subject_name IN ('机械原理','计算机导论');

铁律9:索引中不包含NULL值,所以使用IS NULL、IS NOT NULL做判断的条件,都用不到索引

解决方法:应该将数据库中的所有字段都设置为不可为NULL,且针对不同的数据类型设置默认值。
比如,对于INT类型的字段,如果为NULL,则设为默认值0。这样就可以将IS NULL的判断,转换为与0相等的判断。 如:
SELECT * FROM score WHERE score IS NULL;
转换为:
SELECT * FROM score WHERE score = 0;

铁律10: INT型字段中,应该使用>=替换>

如:
SELECT * FROM student WHERE age > 15;
转换为:
SELECT * FROM student WHERE age >= 16;

铁律11: 在多个结果集不交叉的情况下,使用UNION ALL替换UNION

如:
SELECT * FROM score WHERE score = 100
UNION
SELECT * FROM score WHERE score = 99;
转换为:
SELECT * FROM score WHERE score = 100
UNION ALL
SELECT * FROM score WHERE score = 99;

铁律12: 优化GROUP BY子句

如:
SELECT trans_date,stock_code,sum(volume)
FROM stock_trans_detail
GROUP BY trans_date,
CASE WHEN trans_type = 'B' THEN '买入' WHEN trans_type = 'S' then '卖出'
ELSE '' END
HAVING trans_date BETWEEN '2020-01-01' AND '2020-12-31';
转换为:
SELECT trans_date,
CASE WHEN trans_type = 'B' THEN '买入' WHEN trans_type = 'S' then '卖出'
ELSE '' END, SUM(volume)
FROM stock_trans_detail
WHERE trans_date BETWEEN '2020-01-01' AND '2020-12-31'
GROUP BY trans_date,trans_type;

铁律13: 使用ORDER BY配合LIMIT分页查询

如:
当LIMIT的偏移量特别大时,效率会非常低
SELECT * FROM score LIMIT 1000,10 效率高
SELECT * FROM score LIMIT 100000,10 效率低
转换为:
SELECT * FROM score ORDER BY student_id LIMIT 100000,10;

铁律14: 避免不合理的DISTINCT

由于DISTINCT去重功能的限制,实际开发过程中使用到DISTINCT的情况很少。如果发现结果集有重复而需要使用DISTINCT去重,
则很可能是因为对业务逻辑理解不足导致的SQL语句的编写问题。 如:
SELECT DISTINCT a.stock_code,a.stock_name
FROM stock a
INNER JOIN stock_trans_detail b
ON a.stock_code = b.stock_code
AND b.trans_date BETWEEN '2020-01-01' AND '2020-12-31‘;
转换为:
SELECT a.stock_code,a.stock_name FROM stock a
WHERE EXISTS (
SELECT 1 FROM stock_trans_detail b
WHERE a.stock_code = b.stock_code
AND b.trans_date BETWEEN '2020-01-01' AND '2020-12-31');

铁律15: 不要把SQL语句写的太冗长

合理使用临时表,而不是想着一个SQL解决所有问题。如果一个SQL关联的表超过5张,就应该考虑拆分。

SQL进阶-索引设置&sql优化的更多相关文章

  1. 「MySQL高级篇」explain分析SQL,索引失效&&常见优化场景

    大家好,我是melo,一名大三后台练习生 专栏回顾 索引的原理&&设计原则 欢迎关注本专栏:MySQL高级篇 本篇速览 在我们上一篇文章中,讲到了索引的原理&&设计原则 ...

  2. 面试题: mysql 数据库已看 sql安全性 索引 引擎 sql优化

    总结的一些MySQL数据库面试题 2016年06月16日 11:41:18 阅读数:4950 一.sql语句应该考虑哪些安全性? (1)防止sql注入,对特殊字符进行转义,过滤或者使用预编译的sql语 ...

  3. SQL Server 索引维护sql语句

    使用以下脚本查看数据库索引碎片的大小情况: 复制代码代码如下: DBCC SHOWCONTIG WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS  以 ...

  4. SQL Server2005索引碎片分析和解决方法

    SQL Server2005索引碎片分析和解决方法 本文作者(郑贤娴),请您在阅读本文时尊重作者版权. 摘要: SQL Server,为了反应数据的更新,需要维护表上的索引,因而这些索引会形成碎片.根 ...

  5. 【译】SQL Server索引进阶第八篇:唯一索引

    原文:[译]SQL Server索引进阶第八篇:唯一索引     索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就 ...

  6. SQL优化的四个方面,缓存,表结构,索引,SQL语句

    一,缓存 数据库属于 IO 密集型的应用程序,其主要职责就是数据的管理及存储工作.而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个IO是在毫秒级别,二者相差3个数量级.所 ...

  7. SQL Server索引进阶:第十三级,插入,更新,删除

    在第十级到十二级中,我们看了索引的内部结构,以及改变结构造成的影响.在本文中,继续查看Insert,update,delete和merge造成的影响.首先,我们单独看一下这四个命令. 插入INSERT ...

  8. SQL Server索引进阶:第九级,读懂执行计划

    原文地址: Stairway to SQL Server Indexes: Level 9,Reading Query Plans 本文是SQL Server索引进阶系列(Stairway to SQ ...

  9. SQL Server索引进阶:第五级,包含列

    原文地址: Stairway to SQL Server Indexes: Level 5, Included Columns 本文是SQL Server索引进阶系列(Stairway to SQL ...

随机推荐

  1. tomcat启动完成执行 某个方法 定时任务(Spring)

    第一步引入接口: ServletContextListener @RestController @RequestMapping("/schedule") public class ...

  2. .net Dapper 实践系列(5) ---事务编辑(Layui+Ajax+Dapper+MySQL)

    目录 写在前面 实践步骤 写在前面 上一小节,我们总结了根据Id查询多表数据,最后返回Json对象给前台的例子.接下来,在这一小节我们要实现多表编辑的操作. 实践步骤 因为上一小节以及创建了Edit视 ...

  3. ubuntu ufw相关命令

    引自:http://www.cnblogs.com/jiangyao/archive/2010/05/19/1738909.html 就这句话就够了,下面的可以不看 sudo  ufw enable| ...

  4. springboot 全局异常捕获,异常流处理业务逻辑

    前言 上一篇文章说到,参数校验,往往需要和全局的异常拦截器来配套使用,使得返回的数据结构永远是保持一致的.参数异常springboot默认的返回结构: { "timestamp": ...

  5. python --- Socketserver N部曲(1)

    曲一 socketserver 是为了简化服务器端开发而产生的,是一个高级的标准库.(背景介绍完毕,开始干) 一些概念 来自源码的一张图片,简洁又FengSao +------------+ | Ba ...

  6. Springboot揭秘-快速构建微服务体系-王福强-2016年5月第一次印刷

    JavaConfig项目: spring IOC有一个非常核心的概念——Bean.由Spring容器来负责对Bean的实例化,装配和管理.XML是用来描述Bean最为流行的配置方式.Spring可以从 ...

  7. vue项目使用html5+ barcode扫码在苹果遇到的问题以及自己的解决方法

      之前在记录扫码 在安卓时,会出现黑屏,错位,闪退等等问题.解决方法在另一篇文章里 https://www.cnblogs.com/huzhuhua/p/11064764.html . 当时以为 是 ...

  8. Java深入学习(1):多线程

    多线程目的:在同一时刻有多条不同路径执行程序,提高程序运行效率 多线程应用:数据库连接池,多线程文件下载等 注意:在文件下载中使用多线程,无法提高速度 在一个进程中,一定会有主线程 从基础开始,多线程 ...

  9. setsockopt()函数使用

    closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket BOOL bReuseaddr=TRUE; setsockopt (s,SOL_SOCKET ,SO ...

  10. java虚拟机类加载机制和双亲委派模型

    java虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型. 类的生命周期是从类被加载到虚拟机内存中,到卸 ...