索引的原理与作用,各种书籍和网络上的介绍可以说是铺天盖地,基本上主流数据库系统的也都是一致的。选择索引字段的原则,比如外键字段、数据类型较小的字段、经常用于查询或排序的字段、表关联的字段等等,在此不做赘述。本人在工作中见到过很多人创建的索引,回想自己以前也会有理论知识空洞的体会,总感觉理论知识无法与具体的工作问题相匹配。在此仅以工作学习中积累的一点经验和问题场景整理以飨读者。先把常见的注意事项整理如下:
最后需要提醒的是,不要滥用索引。因为过多的索引不仅仅会增加物理存储的开销,对于插入、删除、更新操作也会增加处理上的开销,而且会增加优化器在选择索引时的计算代价。
因此太多的索引与不充分、不正确的索引对性能都是毫无益处的。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。
举下面一个场景的例子,创建这样的索引是有效的吗?
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)
组合索引 Index(A, B)
附,查询指定数据表的索引定义情况:
--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;