(尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/90736098冷血之心的博客)

关注微信公众号(文强的技术小屋),学习更多技术知识,一起遨游知识海洋~

快速导航:

MySQL原理与实践(一):一条select语句引出Server层和存储引擎层

MySQL原理与实践(二):一条update语句引出MySQL日志系统

MySQL原理与实践(三):由三种数据结构引入MySQL索引及其特性

MySQL原理与实践(四):由数据库事务引出数据库隔离级别

MySQL原理与实践(五):数据库的锁机制

MySQL原理与实践(六):自增主键的使用

目录

前言:

正文:

三种常见的索引数据结构:

哈希表:

有序数组:

搜索树:

InnoDB存储引擎的索引:

B+树的特征:

B+树的优势:

主键索引(聚簇索引):

二级索引(普通索引/非聚簇索引):

回表:

索引的维护:

页分裂和页合并:

自增主键:

重建索引:

重建普通索引k:

重建主键索引:

总结:

InnoDB存储引擎的索引优化:

覆盖索引:

最左前缀原则:

索引下推:

总结:

唯一索引和普通索引:

查询过程

更新过程:

change buffer:

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

数据更新步骤:

change buffer 的使用场景:

索引选择和实践

总结:

使用索引的建议和要求:

结束语:


前言:

在前面两章的学习中,我们介绍了MySQL的Server层,存储引擎层以及MySQL的日志模块:redo log和binlog模块。这篇文章,我们将介绍MySQL中另一个重要的模块:索引。如果大家对MySQL稍微有点了解,那么就一定听说过索引。通过第一章 MySQL原理与实践(一):一条select语句引出Server层和存储引擎层的学习,我们知道Server层的执行器调用存储引擎层来查找或者更新数据。而索引就像一本书的目录,是用来加速查找数据的,所以,索引其实是存储引擎层的概念,每一种存储引擎都会有不同的索引,其底层实现也不同。本文整理总结于极客时间 -《MySQL实战45讲》,欢迎大家订阅学习,干货满满。

正文:

索引是为了提高查询的效率,不同的索引其底层数据结构也不同。接下来,我们先介绍三种最常见的索引实现数据结构,即哈希表,有序数组以及搜索树。

三种常见的索引数据结构:

哈希表:

哈希表是一种常见的数据结构,我们常用的HashMap内部实现也是一个哈希表。哈希表由一个Key和Value组成,通过Key可以O(1)的复杂度快速的找到其对应的Value。实现原理上,当我们将数据存入哈希表的时候,根据存入的Key,通过一个指定的哈希算法,得到一个固定的hash值,将其插入到指定的位置。如果多个Key算出的Hash值一样,即发生了hash冲突,那么可以通过一个链表来进行维护。但是,如果hash冲突较多,链表太长的时候也会影响到查找速度,所以JDK8之后做了一些改进措施,当链表长度大于8的时候,会在链表的后边维护一个红黑树来进一步提高查询速度。具体可以参考这篇文章:HashMap实现原理分析。 Hash表底层由数组+链表+红黑树的结构实现,数据并不是有序的,所以只适合做等值查询,区间查询的效率很低。

有序数组:

有序数组在等值查询和区间查询的时候效率都很高,但是只适合于静态的数据,如果由更新数据的需求,则成本太高。

搜索树:

树可以有二叉,也可以有多叉。二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。

以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一个 10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。

总结:索引底层实现的数据结构大都具有一定的特性,那就是有助于提高查询的效率,类似的数据结构还有跳表等。

在前面我们介绍过,索引是在存储引擎层实现的,不同的存储引擎所支持的索引方式是不同的,在MySQL原理与实践(一):一条select语句引出Server层和存储引擎层一文中,我们简单介绍了Memory存储引擎,其默认的索引就是Hash索引。在MySQL众多的存储引擎中,InnoDB因为对行锁和事务的支持,成为了是最常用的存储引擎,所以我们接下来介绍InnoDB的存储引擎。

InnoDB存储引擎的索引:

InnoDB存储引擎的索引底层使用B+树来实现。表都是根据主键顺序以索引的形式存放的,每一个索引在innoDB中都对应着一颗B+树。关于B+树的概念,大家可以参考 漫画:什么是b+树 。这里我们直接总结B+树的特点及其优势:

B+树的特征:

  • 有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点
  • 所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接
  • 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素

B+树的优势:

  • 单一节点存储更多的元素,使得查询的IO次数更少
  • 所有查询都要查找到叶子节点,查询性能稳定
  • 所有叶子节点形成有序链表,便于范围查询

我们先来创建一张表T,主键为id,并且拥有字段k和字段name,k字段上有索引,建表语句如下所示:

create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

执行命令截图如下:

接下来,我们使用如下的语句来插入几条数据:

insert into t values(100,1,'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'dd'),(600,6,'ee');

在InnoDB存储引擎的表中,每一个主键都是一颗索引树,也就是说主键索引是肯定存在的。其次该表中还存在一个k字段上的普通索引。那么我们来看下这两个索引对应的主键索引树和普通索引树。

表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下,左边是主键索引树,右边是k字段上的索引对应的普通索引树。

主键索引(聚簇索引):

InnoDB的主键索引树的叶子节点存储着整行的数据,也就是索引页面指针指向数据页面,这种索引叫做聚簇索引,聚簇索引查找数据几乎总是比使用非聚簇索引快,每张表只能建一个聚簇索引。

二级索引(普通索引/非聚簇索引):

在InnoDB中,普通索引的叶子节点存储的其对应的主键的值,所以也被称为二级索引。

回表:

既然学习索引,肯定得对查询中得一个特殊操作回表得概念有所了解。上边我们说主键索引比普通索引得查询速度快,那么为什么会快呢?因为普通索引树上并没有完整得数据,找到主键后,需要返回到主键索引树上获取所需得数据,这个操作被称为回表。

我们来看一个例子,分别使用主键索引和普通索引:

  • 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
  • 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。

既然说到了回表,有没有聪明的小伙伴想到,如果我没有主键或者我把主键给删除了,是不是就不可以回表了?在InnoDB中,当你没有设主键或者主键突然被删除时,会自动建立一个主键rowid,保证回表等功能的正常运行。

索引的维护:

前面我们说了建立索引可以有效的提高查询效率,那么我们是不是可以为每个查询都建立索引呢?不是的,建立索引可以提高查询效率,但是我们必须考虑到索引的维护代价。从上边的主键索引图中我们可以看到,每一个数据记录都按照主键进行了有序的排列。当我们插入数据的时候,B+树为了维护有序性,需要做一些额外的操作。

页分裂和页合并:

如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID 值为 400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去,这个过程称为页分裂。在这种情况下,性能自然会受影响。除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%。

当然有分裂就有合并。当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。

自增主键:

既然索引的维护的主要代价是由于有序性的维护引起的,那么我们有没有办法可以保证数据有序插入呢?如果每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂,这样就可以减少索引的维护代价。

如果我们以业务逻辑中的字段做为主键,那么基本上是不可能保证是有序插入的。所以,出现了自增主键。 自增主键是指自增列上定义的主键,在建表语句中一般是这么定义的: NOT NULL PRIMARY KEY AUTO_INCREMENT。

       插入新记录的时候可以不指定 ID 的值,系统会获取当前 ID 最大值加 1 作为下一条记录的 ID 值。也就是说,自增主键的插入数据模式,正符合了我们前面提到的递增插入的场景。

在阿里巴巴的开发手册中强烈建议在建表的时候指定使用自增主键,那么自增主键除了可以保证数据的有序插入从而避免了页分裂还有哪些好处呢?

这个可以从空间占用上来思考。如果业务逻辑中有一个手机号码phone,将phone字段做为主键,那么普通索引树的叶子节点将会比使用自增主键大很多。

总结:主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

重建索引:

由于数据页分裂和合并,或者数据被删除,数据页会存在一个空洞的位置,导致空间利用率不高。这个时候我们需要重建索引,提高页面的利用率,使索引更加紧凑。

重建普通索引k:

alter table T drop index k;
alter table T add index(k);

重建主键索引:

alter table T drop primary key;
alter table T add primary key(id);

这个重建主键的过程是不合理的。不论是删除主键还是创建主键,都会将整个表重建。所以连着执行这两个语句的话,第一个语句就白做了。这两个语句,你可以用这个语句代替 : alter table T engine=InnoDB。这个语句表示要重新构建该表,会新建一张表,并且进行数据copy以及删除旧表等一系列操作。

总结:

这里我们主要介绍了主键索引和普通索引,并且给出其对应的索引树;阐述了查询时候的回表操作以及索引维护的代价等。在最后介绍了如何重建普通索引和重建主键索引。

InnoDB存储引擎的索引优化:

在上边的学习中,我们介绍了InnoDB索引的底层实现B+树,主键索引和普通索引的区别以及主键的维护和索引的重建等基本概念。索引是为了提高数据库的查询效率,那么建立索引之后,我们还可以做哪些优化从而更加提高查询效率呢?接下来我们依次介绍基本重要概念:覆盖索引,最左前缀原则以及索引下推。

覆盖索引:

在阿里巴巴Java开发手册中有如下的规定:

那么什么是覆盖索引呢?

如果执行的语句是 select ID from T where k between 3 and 5,这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引。

总结:由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

最左前缀原则:

我们再来看一个阿里巴巴Java开发手册中的建议:

如果我们为每一个查询都建立一个索引,是可以提高查询速度,但是维护的代价太高了。所以,我们一般采用组合索引的手段。我们以(name,age)来建立组合索引,那么索引树的结构如下所示:

组合索引项是按照索引定义里面出现的字段顺序排序的。

  • 当你的逻辑需求是查到所有名字是“张三”的人时,可以快速定位到 ID4,然后向后遍历得到所有需要的结果。
  • 如果你要查的是所有名字第一个字是“张”的人,你的 SQL 语句的条件是"where name like ‘张 %’"。这时,你也能够用上这个索引,查找到第一个符合条件的记录是 ID3,然后向后遍历,直到不满足条件为止。

可以看到,不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。

基于上面对最左前缀索引的说明,我们来讨论一个问题:在建立联合索引的时候,如何安排索引内的字段顺序?

这里我们的评估标准是,索引的复用能力。因为可以支持最左前缀,所以当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。

看到这里,你已经明白了为什么我们建议在建立联合索引的时候,将区分度高的放在左边,因为这样可以使用到最左前缀原则,加快查询效率。

(为了利用最左前缀原则,如果查询顺序和联合索引的顺序不一致,优化器会自动做优化,调整where查询条件的顺序)

索引下推:

我们在一次查询中,使用到了联合索引,并且命中了最左前缀原则。比如下边的查询语句:

select * from user where name like '张 %' and age=10;

我们在(name,age)上建立了联合索引。在联合索引树中,我们首先找到了name是张开头的数据,也就是命中了最左前缀原则。那么我们接下来要怎么做呢?

  • 在 MySQL 5.6 之前,只能从 ID3 开始一个个回表。到主键索引上找出数据行,再对比字段值。
  • MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

有了索引下推的支持,将会直接判断当前联合索引树节点中的age是否等于10,决定要不要回表,提高了查询效率。

总结:

通过覆盖索引,最左前缀原则以及索引下推技术的学习,我们可以在写SQL语句以及建立联合索引的时候有所注意,使得查询更加高效。

唯一索引和普通索引:

 唯一索引:不允许具有索引值相同的行,从而禁止重复的索引或键值。系统在创建该索引时检查是否有重复的键值,并在每次使用 INSERT 或 UPDATE 语句添加数据时进行检查。

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

查询过程

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

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

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

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

因为引擎是按页读写的,所以说,当找到 k=5 的记录的时候,它所在的数据页就都在内存里了。那么,对于普通索引来说,要多做的那一次“查找和判断下一条记录”的操作,就只需要一次指针寻找和一次计算。当然,如果 k=5 这个记录刚好是这个数据页的最后一个记录,那么要取下一个记录,必须读取下一个数据页,这个操作会稍微复杂一些。

但是,对于整型字段,一个数据页可以放近千个 key,因此出现这种情况的概率会很低。所以,我们计算平均性能差异时,仍可以认为这个操作成本对于现在的 CPU 来说可以忽略不计。

更新过程:

change buffer:

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

需要说明的是,虽然名字叫作 change buffer,实际上它是可以持久化的数据。也就是说,change buffer 在内存中有拷贝,也会被写入到磁盘上。

(1)merge操作:

  • 将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge

(2)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 因为减少了随机磁盘访问,所以对更新性能的提升是会很明显的。

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 尽量开大,以确保这个“历史数据”表的数据写入速度。

总结:

这里我们分析了唯一索引和普通索引在查询和更新过程中的不同之处,通过分析change buffer的特点,我们知道在大多数情况下都可以通过change buffer和普通索引来提高效率。

使用索引的建议和要求:

以下是阿里巴巴Java开发手册中对于索引的一些建议和要求:

(1)主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。

  • 说明:pk_ 即primary key;uk_ 即 unique key;idx_ 即index的简称。

(2)业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。

  • 说明:不要以为唯一索引影响了insert速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。

(3)在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可。

  • 说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索引,区分度会高达90%以上,可以使用count(distinct left(列名, 索引长度))/count(*)的区分度来确定。

(4)页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

  • 说明:索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。

(5)如果有order by的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查询性能。

  • 正例:where a=? and b=? order by c; 索引:a_b_c
  • 反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b无法排序。

(6)利用覆盖索引来进行查询操作,避免回表。

  • 说明:如果一本书需要知道第11章是什么标题,会翻开第11章对应的那一页吗?目录浏览一下就好,这个目录就是起到覆盖索引的作用。
  • 正例:能够建立索引的种类分为主键索引、唯一索引、普通索引三种,而覆盖索引只是一种查询的一种效果,用explain的结果,extra列会出现:using index。

(7)建组合索引的时候,区分度最高的在最左边。

  • 正例:如果where a=? and b=? ,a列的几乎接近于唯一值,那么只需要单建idx_a索引即可。
  • 说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? and b=? 那么即使a的区分度更高,也必须把b放在索引的最前列。

(8)防止因字段类型不同造成的隐式转换,导致索引失效。

(9)创建索引时避免有如下极端误解:

  • 宁滥勿缺。认为一个查询就需要建一个索引。
  • 宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。
  • 抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。

结束语:

本文通过三种常见的数据结构来引出了索引,并且以InnoDB存储引擎为例开始介绍,介绍了索引的基本概念和使用,并且介绍了索引的优化技术,我们在平时的使用中应该尽量使用覆盖索引,并且利用最左前缀原则;接着我们由buffer change分析了唯一索引和普通索引的区别于选择;在文章的最后,我们给出了重要的几点索引注意事项。

接下来,我会继续更新MySQL原理与实践的系列文章,欢迎大家关注交流,希望对大家的学习有所帮助。

如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群366533258一起交流学习哦~

本群给大家提供一个学习交流的平台,内设菜鸟Java管理员一枚、精通算法的金牌讲师一枚、Android管理员一枚、蓝牙BlueTooth管理员一枚、Web前端管理一枚以及C#管理一枚。欢迎大家进来交流技术。

关注微信公众号(文强的技术小屋),学习更多技术知识,一起遨游知识海洋~

MySQL原理与实践(三):由三种数据结构引入MySQL索引及其特性相关推荐

  1. flask接口mysql开发例子,使用Flask开发简单接口3–引入MySQL

    在线QQ客服:1922638 专业的SQL Server.MySQL数据库同步软件 在前两篇文章中,我们学习了通过Flask开发GET和POST请求接口,但是尚未实现操作数据库,因此,今天的目的是学习 ...

  2. 【密码学原理与实践】(三)仿射密码 符java代码实现

    仿射密码(Affine Cipher) 转载请著明出处 仿射密码是代换密码的一种特殊情况. 在学习仿射密码之前我们首先需要了解几个定理 定理 同余方程唯一解定理 设a ∈ Zm,对任意的b∈Zm,同余 ...

  3. 三万六千字通关MySQL面试

    本文作者:ThinkWon,感谢提供这么详细的资源. 数据库基础知识 为什么要使用数据库 数据保存在内存 优点:存取速度快 缺点:数据不能永久保存 数据保存在文件 优点:数据永久保存 缺点:1)速度比 ...

  4. 新书介绍 -- 《Redis核心原理与实践》

    大家好,今天给大家介绍一下我的新书 -- <Redis核心原理与实践>. 后端开发的同学应该对Redis都不陌生,Redis由于性能极高.功能强大,已成为业界非常流行的内存数据库. < ...

  5. 架构师技能6:深入MySQL原理-Waiting for table metadata lock引发系统崩溃

    开篇语录:以架构师的能力标准去分析每个问题,过后由表及里分析问题的本质,复盘总结经验,并把总结内容记录下来.当你解决各种各样的问题,也就积累了丰富的解决问题的经验,解决问题的能力也将自然得到极大的提升 ...

  6. 数据库系统原理与实践题库及答案(完整版)

    数据库系统原理与实践题库及答案 1.简要说明数据.数据库.数据库管理系统和数据库系统的概念. 答:数据:数据库中存储的基本对象是数据(Data),从计算机的角度来看,数据是指能够被计算机存储和处理的符 ...

  7. 【通知】《生成对抗网络GAN原理与实践》代码开源,勘误汇总!

    有三上个月出版了新书<生成对抗网络GAN:原理与实践>,Generative Adversarial Networks(中文名生成对抗网络,简称GAN)自从被提出来后,其发展就非常迅猛,几 ...

  8. mysql中括号_【Java程序猿必备系列】MySQL知识点总结

    点击 隔壁王小猿 关注公众号获取更多精彩JAVA文章 1.数据库的组成 2.MySQL数据类型 MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 2.1 数值类型 My ...

  9. mysql教程网易云课堂_网易云课堂《MySQL从入门到精通》2017

    『课程目录』: 1.MySQL数据库的基础认识以及地位 2.MySQL的安装目录以及目录功能介绍 3.MySQL环境变量的配置及连接数据库 4.MySQL连接以及各数据库名词介绍 5.MySQL语句的 ...

  10. 负载均衡原理与实践详解 第三篇 服务器负载均衡的基本概念-网络基础

    负载均衡原理与实践详解 第三篇 服务器负载均衡的基本概念-网络基础 系列文章: 负载均衡详解第一篇:负载均衡的需求 负载均衡详解第二篇:服务器负载均衡的基本概念-网络基础 负载均衡详解第三篇:服务器负 ...

最新文章

  1. MySQL联合查询语法内联、左联、右联、全联
  2. Codeforces 813B The Golden Age(数学+枚举)
  3. javascript 网页设计 怎么在同一位置显示几张不同的图片(图片自动变换)
  4. Python实现ARP欺骗
  5. Dubbo自定义日志拦截器
  6. 23-爬虫之scrapy框架增量式实时监测数据爬取10
  7. elasticsearch系列五:搜索详解(查询建议介绍、Suggester 介绍)
  8. 文献记录(part75)--基于最大平均熵率的大数据关联聚类算法
  9. html asp textbox,ASP.NET中 TextBox 文本输入框控件的使用方法
  10. JS实时检测文本框内容长度
  11. android程序导入虚拟机,android项目打包成apk应用程序后部署到虚拟机上测试
  12. SAP License:MM常用事物码
  13. 停止做这7件事,你的工作效率至少翻一倍!
  14. 我学Delphi心得及笔记----用户自定义数据类型(第三讲)
  15. 回调函数的概念及使用
  16. Linux如何磁盘分区
  17. 数学----第一个重要极限证明
  18. java指定日期计算一年内第几天和给出一年内第几天算出指定日期
  19. c语言写拼图游戏算法,[原创]拼图游戏移动算法,简单易懂
  20. 华为重度渗透的欧洲,美国如何清剿?

热门文章

  1. Java经典书籍推荐
  2. [ 代码审计篇 ] 代码审计思路 详解
  3. ES dynamic mapping(动态映射)
  4. Unity 坐标转换
  5. Js网络视频播放器之VideoJsckplayer(直播拉流rtmp、hls)
  6. 水溶性CdseTe ZnS量子点
  7. 这些个适合oier的网站丫太有趣了吧(不定期更新中)
  8. java抽象和接口的理解_Java学习笔记16---抽象类与接口的浅显理解
  9. 数据库复杂查询,左联右联 聚合 计数 时间查询等,持续更新
  10. 服务器每天自动变密码,Windows自动修改系统密码分享