数据库中的聚集索引、非聚集索引、优化索引

这篇文章我们来讨论一下索引的问题吧,这篇文章不会介绍怎么创建索引,但是会介绍怎么优化索引。

什么是索引?

索引是对记录按照多个字段进行排序的一种方式。对表中的某个字段建立索引会创建另一种数据结构,其中保存着字段的值,每个值又指向与它相关的记录。这种索引的数据结构是经过排序的,因而可以对其执行二分查找。

怎么理解索引呢?我们经常用在windows系统下,查询某些文件,系统都会建议我们建立文件的索引。比如,如果你要查询一个文件名,系统要扫描所有文件进行傻瓜式地扫描,速度当然会很慢。当我们建立了索引后,经过相关的算法分析,会很快查询出我们想要的文件名。

我们知道了索引的定义后,下面我们谈谈聚集索引、非聚集索引。

聚集索引、非聚集索引

聚集索引

聚集索引是数据表中按照某个列的顺序来排序。即一个表中创建了聚集索引,则表的默认排序按照此列来排序。

一个表只能有一个聚集索引,因为表的默认排序只能有一个。

非聚集索引

非聚集索引具有独立于数据行的结构。非聚集索引中的项目按索引键值的顺序存储,而表中的信息按另一种顺序存储(这可以由聚集索引规定)。对于非聚集索引,可以为在表非聚集索引中查找数据时常用的每个列创建一个非聚集索引。

查询优化器

查询优化器在执行查询时通常会选择最有效的方法。 但如果没有索引,则查询优化器必须扫描表。您的任务是设计并创建最适合您的环境的索引,以便查询优化器可以从多个有效的索引中选择。

优化索引

(这些都是网上找的,这里做一些记录)

(1)负向条件查询不能使用索引

select * from order where status!=0 and stauts!=1

not in/not exists 都不是好习惯

可以优化为 in 查询:

select * from order where status in(2,3)

(2)前导模糊查询不能使用索引

select * from order where desc like ‘%XX‘

而非前导模糊查询则可以:

select * from order where desc like ‘XX%‘

(3)数据区分度不大的字段不宜使用索引

select * from user where sex=1

原因:性别只有男,女,每次过滤掉的数据很少,不宜使用索引。

经验上,能过滤 80% 数据时就可以使用索引。对于订单状态,如果状态值很少,不宜使用索引,如果状态值很多,能够过滤大量数据,则应该建立索引。

(4)在属性上进行计算不能命中索引

select * from order where YEAR(date) < = ‘2017‘

即使date上建立了索引,也会全表扫描,可优化为值计算:

select * from order where date < = CURDATE()

或者:

select * from order where date < = ‘2017-01-01‘

(5)如果业务大部分是单条查询,使用Hash索引性能更好,例如用户中心

select * from user where uid=?
select * from user where login_name=?

原因:

B-Tree索引的时间复杂度是O(log(n))

Hash索引的时间复杂度是O(1)

(6)允许为null的列,查询有潜在大坑

单列索引不存null值,复合索引不存全为null的值,如果列允许为null,可能会得到“不符合预期”的结果集

select * from user where name != ‘shenjian‘

如果name允许为null,索引不存储null值,结果集中不会包含这些记录。

所以,请使用 not null 约束以及默认值。

(7)复合索引最左前缀,并不是值SQL语句的where顺序要和复合索引一致

用户中心建立了(login_name, passwd)的复合索引

select * from user where login_name=? and passwd=?
select * from user where passwd=? and login_name=?

都能够命中索引

 

select * from user where login_name=?

也能命中索引,满足复合索引最左前缀

select * from user where passwd=?

不能命中索引,不满足复合索引最左前缀

(8)使用ENUM而不是字符串

ENUM保存的是TINYINT,别在枚举中搞一些“中国”“北京”“技术部”这样的字符串,字符串空间又大,效率又低。

(9)如果明确知道只有一条结果返回,limit 1能够提高效率

select * from user where login_name=?

可以优化为:

select * from user where login_name=? limit 1

原因:

你知道只有一条结果,但数据库并不知道,明确告诉它,让它主动停止游标移动

(10)把计算放到业务层而不是数据库层,除了节省数据的CPU,还有意想不到的查询缓存优化效果

select * from order where date < = CURDATE()

这不是一个好的SQL实践,应该优化为:

$curDate = date(‘Y-m-d‘);
$res = mysql_query(‘select * from order where date < = $curDate‘);

原因:

释放了数据库的CPU

多次调用,传入的SQL相同,才可以利用查询缓存

(11)强制类型转换会全表扫描

select * from user where phone=13800001234

你以为会命中phone索引么?大错特错了,这个语句究竟要怎么改?

末了,再加一条,不要使用select *(潜台词,文章的SQL都不合格 =_=),只返回需要的列,能够大大的节省数据传输量,与数据库的内存使用量哟。

时间: 2024-09-30 03:16:57

数据库中的聚集索引、非聚集索引、优化索引的相关文章

Mysql 索引实现原理. 聚集索引, 非聚集索引

Mysql索引实现: B-tree,B是balance,一般用于数据库的索引.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.而B+tree是B-tree的一个变种,MySQL就普遍使用B+tree实现其索引结构. 一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上.这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘

SQL Server索引 - 非聚集索引 &lt;第七篇&gt;

一.非聚集索引维护 非聚集索引的行定位器值保持相同的聚集索引值,即使该聚集索引列物理上重新定位后,也是如此. 为了优化这个维护开销,SQL Server添加一个指向旧数据页的指针,以在页面分割之后指向新的数据页面,而不是更新所有相关非聚集索引的行定位器.这样,虽然降低了非聚集索引的维护开销,但是增加了从非聚集索引行到数据行的导航开销,因为添加了一个旧数据页面和信数据页面之间的连接.因此,将聚集索引作为行定位器降低了非聚集索引相关的开销. 二.定义书签查找 当一个查询请求不是优化器选择的非聚集索引

聚集和非聚集索引

聚集和非聚集索引 简单概括: 聚集索引就是以主键创建的索引 非聚集索引就是以非主键创建的索引 区别: 聚集索引在叶子节点存储的是表中的数据 非聚集索引在叶子节点存储的是主键和索引列 使用非聚集索引查询出数据时,拿到叶子上的主键再去查到想要查找的数据.(拿到主键再查找这个过程叫做回表) 非聚集索引也叫做二级索引,不用纠结那么多名词,将其等价就行了~ 非聚集索引在建立的时候也未必是单列的,可以多个列来创建索引. 此时就涉及到了哪个列会走索引,哪个列不走索引的问题了(最左匹配原则-->后面有说) 创建

索引 - 非聚集索引设计指南-转载

非聚集索引包含索引键值和指向表数据存储位置的行定位器. 有关非聚集索引体系结构的详细信息, 请参阅 非聚集索引结构. 可以对表或索引视图创建多个非聚集索引. 通常, 设计非聚集索引是为改善经常使用的没有建立聚集索引的查询的性能. 与使用书中索引的方式相似, 查询优化器在搜索数据值时, 先搜索非聚集索引以找到数据值在表中的位置, 然后直接从该位置检索数据. 这使非聚集索引成为完全匹配查询的最佳选择, 因为索引包含说明查询所搜索的数据值在表中的精确位置的项. 例如, 为了从 Person.Perso

07.索引-非聚集索引(3)-Key Lookup &amp;RID Lookup

如果存在聚集索引并且查找的列不在 非聚集索引的键列中 而在没有聚集索引的表中 使用RID Lookup 书签查找可能因为开销过大导致一些查询直接进行表扫描 聚集索引所有数据都在索引中(数据页也是索引的一部分),因此可以直接通过聚集索引找到所有的列 定位到索引,也就意味着数据找到了 但是非聚集索引定位到索引后,需要在根据索引记录的RID或者Key 查找数据行,势必会导致一次数据页的I/O 数据行过多,形成的数据页IO也会非常大 当数据过大,IO反而可能超过直接进行页扫描的开销,因此系统会选择进行页

05.索引-非聚集索引(1)-聚集表

建立非聚集索引 CREATE NONCLUSTERED INDEX NCIX_Employee001_Department_Organization ON Employee001(Department,Organization); ALTER INDEX NCIX_Employee001_Department_Organization ON Employee001 REORGANIZE 索引情况 SELECT database_id, index_id, index_type_desc, ind

08.索引-非聚集索引(4)-联合索引、覆盖索引

避免书签查找 可以将查询需要的列加入非聚集索引中 联合索引会导致所有的非聚集索引页中都会冗余一份列的数据,尤其是当这些列不作为条件,只作为返回值时候,是一种浪费 因此可以 选择将查询结果需要的列加入覆盖索引 这时候 覆盖的列 只会存在于叶节点中,定位到索引后,直接从页节点返回数据,避免再根据RID 或者Key 读取数据页,可以减少一次IO

前缀索引,一种优化索引大小的解决方案

今天在读一篇关于数据库索引介绍的文章时,该文章提到了前缀索引,对于我这个搞数据库应用开发那么多年的人来说,这个词还真是一个新词,没用过.于是打算研究一番. 前缀索引似乎是MySQL中的一个概念,在SQL Server和Oracle中没提出这个概念.于是就安装了一个MySQL来做实验,搞清楚前缀索引. 前缀索引说白了就是对文本的前几个字符(具体是几个字符在建立索引时指定)建立索引,这样建立起来的索引更小,所以查询更快.有点相当于Oracle中对字段使用Left函数,建立函数索引,只不过MySQL的

06.索引-非聚集索引(2)-堆表

删除聚集索引 DROP INDEX CIX_Employee001_Id ON Employee001 索引情况 SELECT database_id, index_id, index_type_desc, index_depth, index_level, page_count FROM sys.dm_db_index_physical_stats(DB_ID('IndexDB'),OBJECT_ID('Employee001'),null,null,null) TRUNCATE TABLE

ORACLE数据库中创建、删除--同义词、视图、索引、序列

select * from emp; create synonym emp_ny for emp; create public synonym pub_emp_ny for employees;--创建公有同义词 DROP SYNONYM EMP_NY;--删除同义词 DROP PUBLIC SYNONYM PUB_EMP_NY;--删除公有同义词 查看已有同义词 SELECT * FROM SYS.ALL_SYNONYMS WHERE table_name='DIC_TRIPMODE'; CR