选择索引字段的原则,比如外键字段、数据类型较小的字段、经常用于查询或排序的字段、表关联的字段等等
- 索引应该建在选择性高的字段上(键值唯一的记录数/总记录条数),选择性越高索引的效果越好、价值越大,唯一索引的选择性最高;
- 组合索引中字段的顺序,选择性越高的字段排在最前面;
- where条件中包含两个选择性高的字段时,可以考虑分别创建索引,引擎会同时使用两个索引(在OR条件下,应该说必须分开建索引);
- 不要重复创建彼此有包含关系的索引,如index1(a,b,c) 、index2(a,b)、index3(a);
- 组合索引的字段不要过多,如果超过4个字段,一般需要考虑拆分成多个单列索引或更为简单的组合索引;
使用索引的原则
1. 如果没有唯一性要求,可以选择普通索引
2. 如果列上有唯一性要求,可以选择唯一索引
3. 如果是需要模糊搜索,建议选择全文索引
4. 如果有多个条件一起查询,可以选择组合索引
组合索引举例说明:
索引:在对表需要进行查询或者排序操作时,可以对表中某个或者某几个字段添加索引,对
一个字段添加索引就是单个索引,对多个字段添加索引时就是组合索引。
create index A_index on A(id,custName);
给表A的id、custName字段建立组合索引,组合索引对查询条件是单个字段或者两个字段
都起作用,但是有些地方还是要注意:
select * from A where id > 1 and custName = ‘tom’; — 这种情况会走索引
select * from A where id > 1; — 这种情况也会走索引,尽管只是使用了组合索引中一个字段
注* :但是下面的情况就不会走索引
select * from A where custName = ‘tom’; –因为custName位于组合索引的第二个字段
举下面一个场景的例子,创建这样的索引是有效的吗?
select * from t1, t2 where t1.col_1 = t2.ab and t1.col_2 in (12, 38); -- 创建索引如下 create index idx_t1_query on t1(col_1, col_2);
-- 或者仅创建索引如下
create index idx_t1_col2 on t1(col_2);
再比如,该表最常使用的SQL场景有以下两种类型,应该如何创建索引?
select * from t1 where t1.PartId = 'xxxx' and t1.STATE = 2 and t1.PROCID = 'yyyy' select * from t1 where (t.PartId = 'xxxx' or t1.ActualPartId = 'xxxx' ) and t1.STATE = 2 and t1.PROCID = 'yyyy' -- 创建一个“全覆盖的索引”,把查询条件都包含的索引 create index idx_t1_query on t1(partId, actualpartId, state, procid); -- 还是分开创建如下两个索引 create index idx_t1_PartId on t1(partId, state, procid) create index idx_t1_actualPartId on t1(actualpartId, state, procid)
以执行计划和逻辑IO的统计数据显示,两个场景的测试结果都是后者索引有明显的效果,大家有兴趣可以自己测试验证一下。当然,生产环境远比这些要复杂,各表的数据量及数据分布情况也会影响引擎的执行方式,引擎对索引选择与要求也会不一样,此处仅以简单语句做示例进行说明。
组合索引查询的各种场景:
组合索引 Index (A, B, C)
- 下面条件可以用上该组合索引查询:
- A>5
- A=5 AND B>6
- A=5 AND B=6 AND C=7
- A=5 AND B=6 AND C IN (2, 3)
- 下面条件将不能用上组合索引查询:
- B>5 ——查询条件不包含组合索引首列字段
- B=6 AND C=7 ——理由同上
- 下面条件将能用上部分组合索引查询:
- A>5 AND B=2 ——当范围查询使用第一列,查询条件仅仅能使用第一列
- A=5 AND B>6 AND C=2 ——范围查询使用第二列,查询条件仅仅能使用前二列
- A=5 AND B IN (2, 3) AND C=2 ——理由同上
组合索引排序的各种场景:
组合索引 Index(A, B)
- 下面条件可以用上组合索引排序:
- ORDER BY A ——首列排序
- A=5 ORDER BY B ——第一列过滤后第二列排序
- ORDER BY A DESC , B DESC ——注意,此时两列以相同顺序排序
- A>5 ORDER BY A ——数据检索和排序都在第一列
- 下面条件不能用上组合索引排序:
- ORDER BY B ——排序在索引的第二列
- A>5 ORDER BY B ——范围查询在第一列,排序在第二列
- A IN(1,2) ORDER BY B ——理由同上
- ORDER BY A ASC , B DESC ——注意,此时两列以不同顺序排序
索引合并的简单说明:
- 数据库能同时使用多个索引
- SELECT * FROM TB WHERE A=5 AND B=6
- 能分别使用索引(A) 和 (B);
- 对于这个语句来说,创建组合索引(A,B) 更好;
- 最终是采用组合索引,还是两个单列索引?主要取决于应用系统中是否存在这类语句:SELECT * FROM TB WHERE B=6
- SELECT * FROM TB WHERE A=5 OR B=6
- 组合索引(A, B)不能用于此查询(目前的数据库也很智能,部分OR条件也能够使用组合索引,但效果不是很稳定);
- 很明显,分别创建索引(A) 和 (B)会更好;
- SELECT * FROM TB WHERE A=5 AND B=6
- 删除无效的冗余索引
- TB表有两个索引(A, B) 和 (A),对应两种SQL语句:SELECT * FROM TB WHERE A=5 AND B=6 和 SELECT * FROM TB WHERE A=5
- 执行时,并不是WHERE A=5 就用 (A); WHERE A=5 AND B=6 就用 (A, B);
- 其查询优化器会使用其中一个以前常用索引,要么都用(A, B), 要么都用 (A)。
- 所以应该删除索引(A),它已经被(A, B)包含了,没有任何存在的必要。
- TB表有两个索引(A, B) 和 (A),对应两种SQL语句:SELECT * FROM TB WHERE A=5 AND B=6 和 SELECT * FROM TB WHERE A=5
附,查询指定数据表的索引定义情况:
--Sqlserver: sp_helpindex 'tableName' --或者 select t2.name tabName, t3.name indName, t4.name colName, t1.* from sys.index_columns t1 join sys.tables t2 on t1.object_id = t2.object_id join sys.indexes t3 on t2.object_id = t3.object_id and t1.index_id = t3.index_id join sys.columns t4 on t2.object_id = t4.object_id and t1.column_id = t4.column_id where t2.name = 'tableName' order by t3.name, t1.index_column_id
--Oracle: select * from user_ind_columns a where a.TABLE_NAME = upper('tableName') order by a.INDEX_NAME, a.COLUMN_POSITION;
使用索引需要注意以下几点:
1. 按需使用索引
2. 索引所在的列基数越大越好 , 男女这种字段建立索引的效果并不大 ,基数很小
3.在组合索引上要注意最左原则
我们想要知道我们的sql语句写的好不好,怎么来判断?
我们先说下sql语句是怎么执行的,举个例子
select u.name i.expression from user u left join userinfo i on u.id=i.uid where u.id in (1,3,4,55,67,76) order by u.id limit 10;
这条sql语句,会先执行哪一块? 执行的原理是什么?
select u.name i.expression from user u left join userinfo i on u.id=i.uid where u.id in (1,3,4,55,67,76) order by u.id limit 10;
sql语句执行的逻辑是这样的
第一步: 将user表和 userinfo表 做笛卡尔积
1.FROM 子句对其后面的左表user和右表执userinfo行笛卡尔积, 产生虚拟表VT1
2.ON 子句对VT1中的数据根据ON的条件进行过滤,产生虚拟表VT2
问题:怎么过滤的?
3.JOIN子句 将未符合条件的保留表中的数据添加都VT2中,形成VT3
4.WHERE子句 对VT3中的数据进行WHERE条件过滤,形成VT4
5.GROUP BY 子句对VT4中的数据进行分组操作,然后形成VT5
6.CUBE | ROLLUP 子句进行操作形成VT6
7.HAVING 对VT6中的数据进行HAVING 条件过滤,然后形成VT7
8.SELECT 从VT7中选择要获取的字段,然后形成VT8
9.DISTINCT 去重数据,形成VT9
10.ORDER BY 对VT9的结果排序后,形成VT10
11.LIMIT 从VT10中取出指定的数据,形成VT11,返回给用户
我们想要知道我们的sql语句写的好不好,怎么来判断?
方法一: 直接在数据库上测试,看看执行时间
方法二: explain select xxxx 查看
其中需要关注的几个参数:
type 的值有多个
const:表最多有一个匹配行,const用于比较primary key 或者unique索引。
eq_ref:它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY”。
eq_ref可以用于使用=比较带索引的列。
ref 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。
range 给定范围内的检索,使用一个索引来检查行。
ref列显示使用哪个列或常数与key一起从表中选择行。
rows 显示MYSQL执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引。
建立索引的缺点:
不能因为建索引可以提高查询效率,就建立很多索引,建索引一方面要占用物理存储空间,另一方面
在进行dml操作(插入、更新、删除)时,会降低效率。
参考资料:http://mp.weixin.qq.com/s/jRzYSEG0haf2phMaBNnVkg,
http://www.cnblogs.com/zhaoguan_wang/p/4604025.html?utm_source=tuicool&utm_medium=referral