精华内容
下载资源
问答
  • 昨天有位同事说,他的网页查询过程中发现普通索引和唯一索引的效率是有差别的,普通索引比唯一索引
  • 深入理解四种数据库索引类型(- 唯一索引/非唯一索引 - 主键索引(主索引) - 聚集索引/非聚集索引 - 组合索引) 唯一索引/非唯一索引 主键索引(主索引) 聚集索引/非聚集索引 组合索引 唯一索引/非唯一索引 ...

    深入理解四种数据库索引类型(- 唯一索引/非唯一索引 - 主键索引(主索引) - 聚集索引/非聚集索引 - 组合索引)

    • 唯一索引/非唯一索引
    • 主键索引(主索引)
    • 聚集索引/非聚集索引
    • 组合索引

    唯一索引/非唯一索引

    唯一索引

    1.唯一索引是在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中不可以重复。

    非唯一索引

    2.非唯一索引是在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中可以重复,不要求唯一。

    主键索引(主索引)

    3.主键索引(主索引)是唯一索引的特定类型。表中创建主键时自动创建的索引 。一个表只能建立一个主索引。

    聚集索引/非聚集索引

    4.聚集索引(聚簇索引),表中记录的物理顺序与键值的索引顺序相同。一个表只能有一个聚集索引。

    扩展:聚集索引和非聚集索引的区别?分别在什么情况下使用?

    聚集索引和非聚集索引的根本区别是表中记录的物理顺序和索引的排列顺序是否一致。

    聚集索引的表中记录的物理顺序与索引的排列顺序一致

    优点是查询速度快,因为一旦具有第一个索引值的记录被找到,具有连续索引值的记录也一定物理的紧跟其后。

    缺点是对表进行修改速度较慢,这是为了保持表中的记录的物理顺序与索引的顺序一致,而把记录插入到数据页的相应位置,必须在数据页中进行数据重排,降低了执行速度。在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的分裂调整,十分低效。

    建议使用聚集索引的场合为:
    A.某列包含了小数目的不同值。
    B.排序和范围查找。

    非聚集索引的记录的物理顺序和索引的顺序不一致

    其他方面的区别:
    1.聚集索引和非聚集索引都采用了 B+树的结构,但非聚集索引的叶子层并不与实际的数据页相重叠,而采用中的记录在叶子层包含一个指向表数据页中的指针的方式。聚集索引的叶节点就是数据节点,而非聚集索引的叶节点仍然是索引节点。

    2.非聚集索引添加记录时,不会引起数据顺序的重组。

    看上去聚簇索引的效率明显要低于非聚簇索引, 因为每次使用辅助索引检索都要经过两次 B+树查找, 这不是多此一举吗? 聚簇索引的优势在哪?

    1.由于行数据和叶子节点存储在一起, 这样主键和行数据是一起被载入内存的, 找到叶子节点就可以立刻将行数据返回了, 如果按照主键 Id 来组织数据, 获得数据更快。

    2.辅助索引使用主键作为"指针", 而不是使用地址值作为指针的好处是, 减少了当出现行移动或者数据页分裂时,辅助索引的维护工作, InnoDB 在移动行时无须更新辅助索引中的这个"指针"。 也就是说行的位置会随着数据库里数据的修改而发生变化, 使用聚簇索引就可以保证不管这个主键 B+树的节点如何变化, 辅助索引树都不受影响。

    建议使用非聚集索引的场合为:
    a.此列包含了大数目的不同值;
    b.频繁更新的列

    5.组合索引(联合索引)

    基于多个字段而创建的索引就称为组合索引。

    创建索引
    create index idx1 on table1(col1,col2,col3)
    查询
    select * from table1 where col1= A and col2= B and col3 = C
    

    组合索引查询的各种场景
    组合索引 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 ——注意, 此时两列以不同顺序排序

    alter table users add index lname_fname_age(lname,fname,age);
    

    创建了 lname_fname_age 多列索引,相当于创建了(lname)单列索引,
    (lname,fname)联合索引以及(lname,fname,age)联合索引。

    举例说明:上面给出一个多列索引(username,password,last_login),当
    三 列 在 where 中 出 现 的 顺 序 如 (username,password,last_login) 、
    (username,password)、(username)才能用到索引,如下面几个顺序
    (password,last_login) 、 (passwrod) 、 (last_login)--- 这 三 者 不 从
    username 开始,(username,last_login)---断层,少了 password,都无
    法利用到索引。因为 B+tree 多列索引保存的顺序是按照索引创建的顺序,
    检索索引时按照此顺序检索。



    作者:六尺帐篷
    链接:https://www.jianshu.com/p/f49ee80c4956
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • 普通索引与唯一索引

    万次阅读 多人点赞 2019-04-08 20:20:06
    所谓唯一索引,就是在创建索引时,限制索引的值必须是唯一的。通过该类型的索引可以更快速地查询某条记录。 普通索引还是唯一索引? 假设你在维护一个市民系统,每个人都有一个唯一的身份证号,而且业务代码已经...

    所谓普通索引,就是在创建索引时,不附加任何限制条件(唯一、非空等限制)。该类型的索引可以创建在任何数据类型的字段上。

    所谓唯一索引,就是在创建索引时,限制索引的值必须是唯一的。通过该类型的索引可以更快速地查询某条记录。

    普通索引还是唯一索引?

    假设你在维护一个市民系统,每个人都有一个唯一的身份证号,而且业务代码已经保证了不会写入两个重复的身份证号。如果市民系统需要按照身份证号查姓名,就会执行类似这样的SQL语句:

    select name from CUser where id_card='xxxxxxxyyyyyyzzzzz';

    所以你一定会考虑在id_card字段上建索引。由于身份证号字段比较大,这里不建议将身份证号当做主键,现在有两个选择,要么给id_card字段创建唯一索引,要么创建一个普通索引。如果业务代码已经保证了不会写入重复的身份证号,那么这两个选择逻辑上都是正确的。

    现在需要思考的是,从性能的角度考虑,我们应该选择唯一索引还是普通索引?选择的依据又是什么呢?我们以<深入浅出索引(上)>中的例子来说明,假设字段k上的值都不重复。

    InnoDB的索引组织结构

    接下来,我们就从这两种索引对查询语句和更新语句的性能影响来进行分析。

    查询过程

    假设,执行的查询语句是select id from T where k=5。这个查询语句在索引树上查找的过程,先是通过B+树从树根开始,按层搜索到叶子节点,也就是图中右下角的这个数据页,然后可以认为数据页内部通过二分法来定位记录。

    • 对于普通索引来说,查找到满足条件的第一个记录(5, 500)后,需要查找下一个记录,直到碰到第一个不满足k=5条件的记录。
    • 对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

    那么,这个不同带来的性能差距会有多少呢?答案是,微乎其微

    我们都知道,InnoDB的数据是按数据页为单位来读写的。也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。在InnoDB中,每个数据页的大小默认是16KB。

    因为引擎是按页读写的,所以说,当找到k=5的记录的时候,它所在的数据页就都在内存里了。那么,对于普通索引来说,要多做的那一次“查找和判断下一条记录”的操作,就只需要一次指针寻找和一次计算。

    当然,如果k=5这个记录刚好是这个数据页的最后一个记录,那么要取下一个记录,必须读取下一个数据页,这个操作会稍微复杂一些。但是我们之前计算过,对于整型字段,一个数据页可以放近千个key,因此出现这种情况的概率会很低。所以,我们计算平均性能差异时,仍然可以认为这个操作成本对于现在的CPU来说可以忽略不计。

    更新过程

    为了说明普通索引和唯一索引对更新语句性能的影响这个问题,需要先了解一下change buffer的概念:

    当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。

    需要说明的是,虽然名字叫作change buffer,实际上它是可以持久化的数据。也就是说,change buffer在内存中有拷贝,也会被写入到磁盘上。将change buffer中的操作应用到原数据页,得到最新结果的过程称为merge。除了访问这个数据页会触发merge外,系统有后台线程会定期merge。在数据库正常关闭(shutdown)的过程中,也会执行merge操作。

    显然,如果能够将更新操作先记录在change buffer,减少读磁盘,语句的执行速度会得到明显的提升。而且,数据读入内存是需要占用buffer pool的,所以这种方式还能够避免占用内存,提高内存利用率。

    那么,什么条件下可以使用change buffer呢?

    对于唯一索引来说,所有的更新操作都要先判断这个操作是否违反唯一性约束。比如,要插入(4, 400)这个记录,就要先判断现在表中是否已经存在k=4的记录,而这必须要将数据页读入内存才能判断。如果都已经读入到内存了,那直接更新内存会更快,就没必要使用change buffer了。因此,唯一索引的更新就不能使用change buffer,实际上也只有普通索引可以使用。

    change buffer用的是buffer pool里的内存,因此不能无限增大。change buffer的大小,可以通过参数innodb_change_buffer_max_size来动态设置。这个参数设置为50的时候,表示change buffer的大小最多只能占用buffer pool的50%。

    现在,我们已经理解了change buffer的机制,我们再回过头来分析这个问题,如果要在这张表中插入一个新记录(4, 400)的话,InnoDB的处理流程是怎样的。

    第一种情况是,这个记录要更新的目标页在内存中。这时,InnoDB的处理流程如下:

    • 对于唯一索引来说,找到3和5之间的位置,判断到没有冲突,插入这个值,语句执行结束。
    • 对于普通索引来说,找到3和5之间的位置,插入这个值,语句执行结束。

    这样看来,普通索引和唯一索引对更新语句性能影响的差别,只是一个判断,只会耗费微小的CPU时间。但是,这不是我们关注的重点。

    第二种情况是,这个记录要更新的目标页不在内存中。这时,InnoDB的处理流程如下:

    • 对于唯一索引来说,需要将数据页读入内存,判断到没有冲突,插入这个值,语句执行结束。
    • 对于普通索引来说,则是将更新记录在change buffer,语句执行就结束了。

    将数据从磁盘读入内存涉及随机IO的访问,是数据库里面成本最高的操作之一。change buffer因为减少了随机磁盘访问,所以对更新性能的提升会很明显。现实中就发生过这样的事情,有个DBA的同学说,他负责的某个业务的库内存命中率突然从99%降低到75%,整个系统处于阻塞状态,更新语句全部堵住。而探究其原因后,才发现这个业务有大量插入数据的操作,而他在前一天把其中的某个普通索引改成了唯一索引。

    change buffer的使用场景

    通过以上分析,我们了解了使用change buffer对更新过程的加速作用,也清楚了change buffer只限于用在普通索引的场景下,而不适用于唯一索引。那么,现在有一个问题就是:普通索引的所有场景,使用change buffer都可以起到加速作用吗?

    因为merge的时候是真正进行数据更新的时刻,而change buffer的主要目的就是将记录的变更动作缓存下来,所以在一个数据页做merge之前,change buffer记录的变更越多(也就是这个页面上要更新的次数越多),收益就越大。

    因此,对于写多读少的业务来说,页面在写完以后马上被访问的概率比较小,此时change buffer的使用效果最好。这种业务模型常见的就是账单类、日志类系统。

    反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在change buffer,但之后由于马上要访问这个数据页,会立即触发merge过程。这样随机访问IO的次数不会减少,反而增加了change buffer的维护代价。所以,对于这种业务模式来说,change buffer反而起到了副作用。

    索引选择和实战

    回到一开始的问题,普通索引和唯一索引应该怎么选择。其实,这两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响。所以,这里建议尽量选择普通索引。如果所有的更新后,都马上伴随着对这个记录的查询,那么应该关闭change buffer。而在其他情况下,change buffer都能提升更新性能。

    在实际应用中,你会发现,普通索引和change buffer的配合使用,对于数据量大的表的更新优化还是很明显的。特别的,在使用机械硬盘的时候,change buffer这个机制的收效是非常显著的。所以,当你有一个类似“历史数据”的库,并且出于成本考虑用的是机械硬盘时,那你应该特别关注这些表里的索引,尽量使用普通索引,然后把change buffer尽量开大,以确保这个“历史数据”表的数据写入速度。

    change buffer和redo log

    理解了change buffer的原理,我们很容易联想到之前学习的redo log和WAL。我们知道,WAL提升性能的核心机制,也的确是尽量减少随机读写,这两个概念确实容易混淆。所以,这里把它们放到了同一个流程里来说明,便于我们区分这两个概念。

    现在,我们要在表上执行这个插入语句:

    insert into t(id,k) values(id1,k1),(id2,k2);

    这里,我们假设当前k索引树的状态,查找到位置后,k1所在的数据页在内存(InnoDB buffer pool)中,k2所在的数据页不在内存中。如图所示是带change buffer的更新状态图。

    change buffer的更新过程

    分析这条更新语句,你会发现它涉及了四个部分:内存、redo log(ib_log_fileX)、数据表空间(t.ibd)、系统表空间(ibdata1)。

    这条更新语句做了如下的操作(按照图中的数字顺序):

    • Page1在内存中,直接更新内存;
    • Page2没有在内存中,就在内存的change buffer区域,记录下"我要往Page2插入一行"这个信息。
    • 将上述两个动作记入redo log中(图中3和4)。

    做完上面这些,事务就可以完成了。所以,你会看到,执行这条更新语句的成本很低,就是写了两处内存,然后写了一次磁盘(两次操作合在一起写了一次磁盘),而且还是顺序写的。同时,图中的两个虚线箭头,是后台操作,不影响更新的响应时间。那在这之后的读请求,要怎么处理呢?

    比如,我们现在要执行select * from t where k in (k1, k2)。这里,给出了这两个请求的流程图:

    change buffer的读过程

    从图中可以看到:

    • 读Page1的时候,直接从内存返回。这也说明了,WAL之后如果读数据,不一定要读磁盘,也不一定要从redo log里面把数据更新以后才可以返回,图中的状态就反应了,虽然磁盘上还是之前的数据,但是这里直接从内存返回结果,结果是正确的。
    • 要读Page2的时候,需要把Page2从磁盘读入内存中,然后应用change buffer里面的操作日志,生成一个正确的版本并返回结果。

    可以看到,直到需要读Page2的时候,这个数据页才会被读入内存。所以,如果要简单的对比这两个机制在提升更新性能上的收益的话,redo log主要节省的是随机写磁盘的IO消耗(转成顺序写),而change buffer主要节省的则是随机读磁盘的IO消耗。

    总结

    这次,我们从普通索引和唯一索引的选择开始,了解了数据的查询和更新过程,然后说明了change buffer的机制以及应用场景,最好讲到了索引选择的实践。由于唯一索引用不上change buffer的优化机制,因此如果业务可以接收,从性能角度出发还是建议优先考虑非唯一索引。

    最后补充:

    • 首先,业务正确性优先,我们一开始的前提就是"业务代码已经保证不会写入重复数据"的情况下,讨论性能问题。如果业务不能保证,或者业务就是要求数据库来做约定,那么没得选,必须创建唯一索引。这种情况下,本篇文章的意义在于,如果碰上了大量插入数据慢、内存命中率低的时候,可以给你多提供一个排查的思路。
    • 然后,在一些"归档库"的场景,你是可以考虑使用普通索引的。比如,线上数据只需要保留半年,然后历史数据保存在归档库。这时候,归档数据已经是确保没有唯一键冲突了。要提高归档效率,可以考虑把表里面的唯一索引改成普通索引。

    思考:通过change buffer更新过程图可以看到,change buffer一开始是写内存的,那么如果这个时候机器掉电重启,会不会导致change buffer丢失呢?change buffer丢失可不是小事儿,再从磁盘读入数据可就没有了merge过程,就等于是数据丢失了。会不会出现这种情况呢?

    答案:不会丢失。虽然只是更新内存,但是在事务提交的时候,我们把change buffer的操作也记录到了redo log里了,所以崩溃恢复的时候,change buffer也能找回来。

    下面给出merge的执行流程:

    • 从磁盘读入数据页到内存(老版本的数据页)。
    • 从change buffer里找出这个数据页的change buffer记录(可能有多个),依次应用,得到新版数据页。
    • 写redo log。这个redo log包含了数据的变更和change buffer的变更。

    到这里merge过程就结束了。这时候,数据页和内存中change buffer对应的磁盘位置都还没有修改,属于脏页,之后各自刷回自己的物理数据,就是另外一个过程了。

    展开全文
  • 主键索引: 主键索引不可以为空 主键索引可以做外键 一张表中只能有一个主键索引 ...唯一索引: 被索引的数据列不允许包含重复的值 以下内容转载自:https://blog.csdn.net/qq_41618510/article/details/...

    主键索引:

    • 主键索引不可以为空
    • 主键索引可以做外键
    • 一张表中只能有一个主键索引

    普通索引:

    • 用来加速数据访问速度而建立的索引。多建立在经常出现在查询条件的字段和经常用于排序的字段。
    • 被索引的数据列允许包含重复的值

    唯一索引:

    • 被索引的数据列不允许包含重复的值

     

     

    以下内容转载自:https://blog.csdn.net/qq_41618510/article/details/83317969

    查询的优化:

    哈希索引

     InnoDB引擎有一个特殊的功能叫做“自适应哈希索引(adaptive hash index)”。  当InnoDB注意到某些索引值被使用得非常频繁时,它会在内存中基于B-Tree索引之上再创建-一个哈希索引,这样就让B-Tree索引也具有哈希索引的一些优点,比如快速的哈希查找。这是一个完全自动的、内部的行为,用户无法控制或者配置,不过如果有必要,完全可以关闭该功能。


          创建自定义哈希索引。如果存储引擎不支持哈希索引,则可以模拟像InnoDB一样创建哈希索引,这可以享受- -些哈希索引的便利,例如只需要很小的索引就可以为超长的键创建索引。

          思路很简单:在B-Tree基础.上创建-一个伪哈希索引。这和真正的哈希索引不是一回事,因为还是使用B-Tree进行查找,但是它使用哈希值而不是键本身进行索引查找。你需要做的就是在查询的WHERE子句中手动指定使用哈希函数。

          下面是一个实例,  例如需要存储大量的URL,并需要根据URL进行搜索查找。如果使用B-Tree来存储URL,存储的内容就会很大,  因为URL本身都很长。正常情况下会有如下查询:

          mysql> SELECT id FROM url WHERE url="http: //ww.mysq1.com" ;

          若删除原来URL列.上的索引,而新增-一个被索引的url_ crc 列,使用CRC32做哈希,就可以使用下面的方式查询:

    mysql> SELECT id FROM url WHERE url="http://www.mysq1. com"
    AND url_ crc=CRC32("http://www.mysq1.com");

    这样做的性能会非常高,因为MySQL优化器会使用这个选择性很高而体积很小的基于url_ crc列的索引来完成查找(在上面的案例中,索引值为1560514994)。即使有多个记录有相同的索引值,查找仍然很快,只需要根据哈希值做快速的整数比较就能找到索引条目,然后----比较返回对应的行。另外一种方式就是对完整的URL字符串做索引,那样会非常慢。

     

     

    展开全文
  • 我秃了!唯一索引、普通索引我该选谁?

    千次阅读 多人点赞 2021-09-06 00:35:26
    你遇到过不知道如何选择唯一索引和普通索引的场景么?你知道他俩的原理和区别么?来不及了,快上车!!

    小伙伴想精准查找自己想看的MySQL文章?喏 → MySQL江湖路 | 专栏目录
    在这里插入图片描述

      提到唯一索引普通索引,相信大家都不陌生,当同事小姐姐问你这俩有什么区别时?或许你会脱口而出:“这还用问?见名知意啊,一个是允许字段重复,一个不允许存在重复数据!”

      是否解决小姐姐的疑问我不知道,但你在同事心目中,肯定不是啥好玩意儿~ 要知道,一眼就看出的答案,一般不会有人问,除非问傻子~

    那么当你处理一张市民信息表时,其中一列为市民的身份证号信息,你会怎么选择哪个索引?为什么?

      对于一个经历过风风雨雨、日日夜夜的程序员来说,需要你考虑的东西可不仅是重不重复这类问题,而是…

    在这里插入图片描述

    开个玩笑~~应当结合实际情况,对各个场景进行综合考虑。

      其实,如果在业务代码中保证了不会写入重复的身份证号,那么这两个选择逻辑上都是正确的。但是在SELECT和DML场景中,唯一索引和普通索引却有很多不同。

    1、在SELECT中,唯一索引和普通索引的区别

      本文测试引擎选择我们最常用的InnoDB,版本为MySQL8.0;

    假设,执行查询的语句是:

    select id from T where id_card = 666;
    

      (身份证太长,咱们用简单数据做演示)我们知道,MySQL的InnoDB采用的是B+树实现的索引结构,查找过程从B+树的树根起,按层搜索到666所在的叶子节点,然后取出该节点所在的数据页,把数据页读到内存后,通过二分法在数据页中定位id_card=666的行数据。

    在这里插入图片描述

    B+ 树的查找过程如上图:

    1. 将磁盘块1从磁盘加载到内存,发生一次IO ,在内存中使用二分查找方式找到 666 在600和700 之间,锁定磁盘块1的P2 指针。
    2. 通过磁盘块1 的 P2 指针地址把磁盘块3 加载到内存,发生第二次IO ,锁定磁盘块3 的 P2 指针
    3. 通过磁盘块3 的P2指针加载磁盘块7到内存,发生第三次 IO,同时根据二分查找找到666 查询结束。

    普通索引和唯一索引的定位方式:

    • 普通索引:查到第一条id_card=666 后,然后继续往后查找直到碰到第一个 id_card<>666 的记录时,结束。
    • 唯一索引:由于索引定义了唯一性,查找到第一个满足条件的记录后,直接结束。

      两者在查询方面的性能差距微乎其微。对于普通索引多的那一次操作,因为本身就是以数据页为单位读进内存,数据页大小默认16KB(大概1000行),要多做的那一次“查找和判断下一条记录”的操作,就只需要一次指针寻找和一次计算。当然,不可避免查询的数据是该数据页的最后一位,这样还要再读下一块数据页,算法会复杂一些。

      但你知道的,这种概率很小,我们程序员要相信逆墨菲定律:大概率不会出现且未被发现的BUG,在难以改动的前提下,你就当不知道就完了,发生了又能咋地?有测试顶着呢!

    在这里插入图片描述

      有同学问我了:普通索引为什么要继续向下查找?继续向下查找的原因是由于普通索引允许重复值,且B+Tree是天然有序的。SQL中并没有指定limit 1,所以他还要往下查,看是否有同条件的数据一起返回,直到查到第一条不满足条件的数据为止。

    2、在DML中,唯一索引和普通索引的区别

      ding!这是本篇文章的重点,在看之前,我们需要先了解什么是change buffer

      了解MySQL机制的同学们知道,当执行 DML(INSERT、UPDATE、DELETE)等操作时,InnoDB会利用 change buffer进行加速写操作,可以将写操作的随机磁盘访问调整为局部顺序操作,而在机械硬盘时代,随机磁盘访问(随机I/O)也是数据库操作中的最耗性能的硬伤。当普通索引(非唯一索引)的数据页发生写操作时,把操作内容写到内存中的change buffer后就可以立刻返回(执行完成)了。

      这里我以UPDATE操作为例,当需要更新某一行数据时,会先判断该行所在数据页是否在内存中,如果在就直接在内存数据页中更新,如果这个数据页没有内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些UPDATE操作缓存在 change buffer 中,这样就不需要从磁盘读入数据页,当有SQL查询需要访问这个数据页的数据时,将数据页读入内存后,然后先执行 change buffer 中与这个页的相关UPDATE操作,通过这种方式保证这个数据页的逻辑正确性

    在这里插入图片描述

      可见,change buffer是会被从内存持久化到磁盘中的,将 change buffer 中的操作应用到原数据页,得到最新结果的过程被称为 merge。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作,相当于刷脏页啦(把已修改的数据更新到实际数据文件中)。

    触发merge的操作主要有以下几种(你该记住的点):

    • 有SQL线程访问这个数据页;
    • master thread线程每秒或每10秒进行一次merge change buffer的操作;
    • 在数据库正常关闭的时候。

      小朋友,你是否有很多问号??DB服务器宕机,数据不是就丢了?这就得redo log + binlog来保证了,可以参考作者另一篇文章《听我讲完redo log、binlog原理,面试官老脸一红》,本篇不再赘述。

      跑远了?言归正传~~上文提到普通索引(非唯一索引)会使用到change buffer进行加速写操作,你是不是已经get到点了呢~

      是的,唯一索引不会使用 Change buffer ,如果索引设置了唯一属性,在进行插入或者修改操作时,InnoDB 必须进行唯一性检查,如果不读取索引页到缓冲池,无法校验索引是否唯一,如果都把索引页读到内存了,那直接更新内存会更快,就没必要使用change buffer了。

    • 对于普通索引(非唯一索引)的DML操作来说,当待更新的数据页在内存中时,找到前值和后值的区间插入即可;当待更新的数据页在不在内存中时,直接把操作写到Change buffer就完事儿了。舒服!

    • 对于唯一索引,当待更新的数据页在不在内存中时,索引每次都得把数据页读到内存中判断唯一性,将数据从磁盘读入内存涉及大量随机IO的访问,慢的一批,当遇到高频写操作时??唉,别想了,难受!

      到这里,相信你对普通索引和唯一索引的取舍有了一定的概念,普通索引和唯一索引在查询能力上是没差别的,主要考虑的是更新的影响。还得结合实际业务场景来判断,如果是读取远大于更新和插入的表,唯一索引和普通索引都可以,但是如果业务需求相反,个人觉得应该使用普通索引,当然如果是那种更新完要求立即可见的需求,就是刚更新完就要再查询的,这种情况下反而不推荐普通索引,因为这样会频繁的产生merge操作,起不到change buffer的作用,反而需要额外空间来维护change buffer就有点得不偿失了。

      当我们使用普通索引,尤其在使用机械盘的场景下,尽量把change buffer开大从而确保数据的写入速度。最后,通过列举一下 change buffer 的配置,结束今天的分享,相信看到这里的都是有心人,也是喜爱MySQL的崽子,记得不要吝啬你的点赞哦~~

    在这里插入图片描述

    change buffer 配置

    • innodb_change_buffer_max_size% 配置写缓冲的大小,占整个缓冲池的比例,默认值是25%,可以通过修改该值提高InnoDB写效率,最大值是50%。
    mysql> show variables like '%innodb_change_buffer_max_size%';
    +-------------------------------+-------+
    | Variable_name                 | Value |
    +-------------------------------+-------+
    | innodb_change_buffer_max_size | 25    |
    +-------------------------------+-------+
    1 row in set (0.00 sec)
    
    • innodb_change_buffering配置是否缓存辅助索引页的修改,默认为 all,即缓存 INSERT/DELETE/UPDATE等DML操作。
    mysql> show variables like '%innodb_change_buffering%';
    +-------------------------+-------+
    | Variable_name           | Value |
    +-------------------------+-------+
    | innodb_change_buffering | all   |
    +-------------------------+-------+
    1 row in set (0.00 sec)
    

    MySQL系列文章汇总与《MySQL江湖路 | 专栏目录》

    往期热门MySQL系列文章

    展开全文
  • 天天搞数据,聚集索引非聚集索引,唯一索引,非唯一索引,天天见但不理解,网上也找不到几个能说囫囵的。今天处理数据库问题时被老大教育一番,然后给我普及了一数据库索引的知识。 聚集索引 聚集索引的作用对象是...
  • 普通索引和唯一索引的思考

    千次阅读 2019-05-17 09:53:47
    《普通索引和唯一索引的思考》 大家好,我是IT修真院深圳分院java第4期学员,一枚正直善良的java程序员。今天给大家分享一下,修真院官网java任务一中关于普通索引和唯一索引的区别,以及在任务中使用的一些感想...
  • 普通索引 这是最基本的索引类型,而且它没有唯一性之类的限制。 唯一性索引 这种索引和前面的“普通索引”基本相同,...对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索...
  • B树与红黑树最广泛的应用就是数据库索引,熟练使用索引是程序员最重要的基本功之一。索引的数据结构可以是树,也可以是哈希表。常用的数据库都是树结构的索引,本篇的背景也全部以树结构的索引为前提。本文旨在梳理...
  • MongoDB性能篇 -创建索引,组合索引,唯一索引,删除索引和explain执行计划 转载 2015年04月13日 13:02:54 标签: mongodb / 337 编辑 删除 MongoDB性能篇 -创建索引,组合索引,唯一索引...
  • MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes 中,且默认总是为_id创建索引,它的索引使用基本和MySQL 等关系型数据库一样。其实可以这样说说,索引是凌驾于数据存储系统之上的另一层系统,所以...
  • mysql 联合索引和唯一索引

    千次阅读 2015-01-08 21:22:22
    一般来说.如果有where a=? and b=? and c=? 的语句. 如果表也有DML, 我一般只在a 上建索引. 这也是代价平衡的结果. 一方面 只在a 上建索引那么是 ...另一方面,DML也会更新index,更新三个column肯定比更新一个c
  • 索引对数据库性能的影响? 本质:缩小查询范围。大大减少需要扫描的数据量。...主键索引是唯一索引,但唯一索引不是主键索引, 主键可以和外键构成参照完整性约束,防止数据不一致。 mysql索引的创建原则? ...
  • 1.唯一索引在做更新操作的时候,首先要把数据页读入内存中,在数据页中判断有没有跟唯一索引相等的值,如果有就拒绝插入,反之插入成功。 那么什么是数据页呢? InnoDB 在读取数据的时候是按照数据页去读取数据的,...
  • 索引为什么提高了查询的速率,但是update delete insert 的速度会变 因为:这三种操作会破坏二叉树的,所以会造成速度变 什么样的索引使用什么样的方法进行查询 对于模糊查询 1 使用全文索引的目的就是为了...
  • 其主要内容包括唯一索引、B-tree、哈希索引(自定义哈希索引和Innodb自适应哈希索引)和全文索引(自然语言搜索和布尔搜索)。参考书籍和文章是《Mysql技术内幕InnoDB存储引擎》、《高性能Mysql》和《Mysql索引原理...
  • 1.为所有的表建立了唯一索引,索引字段是主键id。 2.对Data表建立组合索引。 建立索引之前,需要花费2.796秒。 建立索引之后,只需要0.136秒。
  • 如题,两张表,关联查询的字段都用设置了唯一索引,因为关联查询时LEFT JION,所以左连接的唯一索引不生效我能理解,但为什么右连接的表的唯一索引也没生效呢,以下附上执行计划截图 结帖:两表排序规则不一致,...
  • 索引 数据库只做两件事情:...索引可能会提高查询速度(如果查询时使用了索引),但一定会减慢写入速度,因为每次写入时都需要更新索引,所以索引只应该加在经常需要搜索的列上,不要加在写多读少的列上。 单列...
  • 这一次,我们主要来聊聊,MySQL中的索引。 MySQL是目前绝大多数互联网公司使用的关系型数据库,它性能出色、资源丰富、成本低廉,是快速搭建互联网应用的首选关系型数据库。但是,俗话说,“好马配好鞍”,仅仅会...
  • MongoDB索引说明及查询优化

    千次阅读 2019-05-01 20:42:50
    文章目录索引种类索引语法查询优化第一步:找出查询语句第二步:分析查询第三步:分析explain结果索引优化实战索引建议 索引种类 索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描...
  • 索引概念的理解 索引是对数据库表中一个或多个列(例如,employee 表的姓名 (name) 列)的值进行排序的结构。如果想按特定职员的姓来查找他或她, 则与在表中搜索所有的行相比,索引有助于更快地获取信息,使用索引...
  • ** 因为本人之前一直写的是电子笔记,对自己学会的东西作一个总结,所以基本都是文字,本来想全发成博客的形式,发现全发成博客比较花费时间,而且一直发博客质量不是...索引就是用来提高数据库性能的东西,不用加内...
  • 唯一非聚集索引留着, 再添加一个 非聚集索引,保留两个索引, 终于搞定了. CREATE UNIQUE NONCLUSTERED INDEX [IX_SF_CP_Detail_MAC2] ON [dbo].[SF_Cp_Detail] ( [Mac2] ASC ) WHERE ([MAC2]<>'' AND [MAC2] IS NOT...
  • 文章目录一、考点1、MySQL索引的基础和类型1)索引的基础2)索引对性能的影响3)索引的使用场景4)索引的类型常考题:唯一索引 与主键索引 当前区别是什么?2、延伸1)MySQL索引的创建原则① 最适合索引的列是出现在...
  • MySQL 索引原理及查询优化

    千次阅读 2016-05-19 19:43:28
    我们知道一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重。
  • MySQL的btree索引和hash索引的区别 Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像BTree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率...
  • 需求 在前端表格处需要显示一些附加信息。便要额外连接两张表。...到前端一刷新,好(实际上,这中间隔了大概一周时间,又新增了几十万数据,普遍反应太!),大约需要20+s; 然后,从前端到后...
  • Python 使用唯一索引( on duplicate key update)避免插入重复数据 这是我在python中向数据库中更新的数据。 每分钟大概500条数据,其中(candles,time_stamp,futures_type)会有大量重复数据。 sql_insert = ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 124,403
精华内容 49,761
关键字:

唯一索引更新慢