热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

day43数据库学习egon的博客索引

一介绍为何要有索引?一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们

一 介绍

为何要有索引?

一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重。说起加速查询,就不得不提到索引了。

什么是索引?

索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能
非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。
索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高好几个数量级。
索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

3010 405 15 35 661 6 11 19 21 39 55 100

你是否对索引存在误解?

索引是应用程序设计和开发的一个重要方面。若索引太多,应用程序的性能可能会受到影响。而索引太少,对查询性能又会产生影响,要找到一个平衡点,这对应用程序的性能至关重要。一些开发人员总是在事后才想起添加索引----我一直认为,这源于一种错误的开发模式。如果知道数据的使用,从一开始就应该在需要处添加索引。开发人员往往对数据库的使用停留在应用的层面,比如编写SQL语句、存储过程之类,他们甚至可能不知道索引的存在,或认为事后让相关DBA加上即可。DBA往往不够了解业务的数据流,而添加索引需要通过监控大量的SQL语句进而从中找到问题,这个步骤所需的时间肯定是远大于初始添加索引所需的时间,并且可能会遗漏一部分的索引。当然索引也并不是越多越好,我曾经遇到过这样一个问题:某台MySQL服务器iostat显示磁盘使用率一直处于100%,经过分析后发现是由于开发人员添加了太多的索引,在删除一些不必要的索引之后,磁盘使用率马上下降为20%。可见索引的添加也是非常有技术含量的。

二 索引的原理

一 索引原理

索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。相似的例子还有:查字典,查火车车次,飞机航班等

本质都是:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。

数据库也是一样&#xff0c;但显然要复杂的多&#xff0c;因为不仅面临着等值查询&#xff0c;还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢&#xff1f;我们回想字典的例子&#xff0c;能不能把数据分成段&#xff0c;然后分段查询呢&#xff1f;最简单的如果1000条数据&#xff0c;1到100分成第一段&#xff0c;101到200分成第二段&#xff0c;201到300分成第三段......这样查第250条数据&#xff0c;只要找第三段就可以了&#xff0c;一下子去除了90%的无效数据。但如果是1千万的记录呢&#xff0c;分成几段比较好&#xff1f;稍有算法基础的同学会想到搜索树&#xff0c;其平均复杂度是lgN&#xff0c;具有不错的查询性能。但这里我们忽略了一个关键的问题&#xff0c;复杂度模型是基于每次相同的操作成本来考虑的。而数据库实现比较复杂&#xff0c;一方面数据是保存在磁盘上的&#xff0c;另外一方面为了提高性能&#xff0c;每次又可以把部分数据读入内存来计算&#xff0c;因为我们知道访问磁盘的成本大概是访问内存的十万倍左右&#xff0c;所以简单的搜索树难以满足复杂的应用场景。

二 磁盘IO与预读

前面提到了访问磁盘&#xff0c;那么这里先简单介绍一下磁盘IO和预读&#xff0c;磁盘读取数据靠的是机械运动&#xff0c;每次读取数据花费的时间可以分为寻道时间、旋转延迟、传输时间三个部分&#xff0c;寻道时间指的是磁臂移动到指定磁道所需要的时间&#xff0c;主流磁盘一般在5ms以下&#xff1b;旋转延迟就是我们经常听说的磁盘转速&#xff0c;比如一个磁盘7200转&#xff0c;表示每分钟能转7200次&#xff0c;也就是说1秒钟能转120次&#xff0c;旋转延迟就是1/120/2 &#61; 4.17ms&#xff1b;传输时间指的是从磁盘读出或将数据写入磁盘的时间&#xff0c;一般在零点几毫秒&#xff0c;相对于前两个时间可以忽略不计。那么访问一次磁盘的时间&#xff0c;即一次磁盘IO的时间约等于5&#43;4.17 &#61; 9ms左右&#xff0c;听起来还挺不错的&#xff0c;但要知道一台500 -MIPS&#xff08;Million Instructions Per Second&#xff09;的机器每秒可以执行5亿条指令&#xff0c;因为指令依靠的是电的性质&#xff0c;换句话说执行一次IO的时间可以执行约450万条指令&#xff0c;数据库动辄十万百万乃至千万级数据&#xff0c;每次9毫秒的时间&#xff0c;显然是个灾难。下图是计算机硬件延迟的对比图&#xff0c;供大家参考&#xff1a;

 

考虑到磁盘IO是非常高昂的操作&#xff0c;计算机操作系统做了一些优化&#xff0c;当一次IO时&#xff0c;不光把当前磁盘地址的数据&#xff0c;而是把相邻的数据也都读取到内存缓冲区内&#xff0c;因为局部预读性原理告诉我们&#xff0c;当计算机访问一个地址的数据的时候&#xff0c;与其相邻的数据也会很快被访问到。每一次IO读取的数据我们称之为一页(page)。具体一页有多大数据跟操作系统有关&#xff0c;一般为4k或8k&#xff0c;也就是我们读取一页内的数据时候&#xff0c;实际上才发生了一次IO&#xff0c;这个理论对于索引的数据结构设计非常有帮助。

三 索引的数据结构

前面讲了索引的基本原理&#xff0c;数据库的复杂性&#xff0c;又讲了操作系统的相关知识&#xff0c;目的就是让大家了解&#xff0c;任何一种数据结构都不是凭空产生的&#xff0c;一定会有它的背景和使用场景&#xff0c;我们现在总结一下&#xff0c;我们需要这种数据结构能够做些什么&#xff0c;其实很简单&#xff0c;那就是&#xff1a;每次查找数据时把磁盘IO次数控制在一个很小的数量级&#xff0c;最好是常数数量级。那么我们就想到如果一个高度可控的多路搜索树是否能满足需求呢&#xff1f;就这样&#xff0c;b&#43;树应运而生&#xff08;B&#43;树是通过二叉查找树&#xff0c;再由平衡二叉树&#xff0c;B树演化而来&#xff09;。

如上图&#xff0c;是一颗b&#43;树&#xff0c;关于b&#43;树的定义可以参见B&#43;树&#xff0c;这里只说一些重点&#xff0c;浅蓝色的块我们称之为一个磁盘块&#xff0c;可以看到每个磁盘块包含几个数据项&#xff08;深蓝色所示&#xff09;和指针&#xff08;黄色所示&#xff09;&#xff0c;如磁盘块1包含数据项17和35&#xff0c;包含指针P1、P2、P3&#xff0c;P1表示小于17的磁盘块&#xff0c;P2表示在17和35之间的磁盘块&#xff0c;P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非叶子节点只不存储真实的数据&#xff0c;只存储指引搜索方向的数据项&#xff0c;如17、35并不真实存在于数据表中。

###b&#43;树的查找过程
如图所示&#xff0c;如果要查找数据项29&#xff0c;那么首先会把磁盘块1由磁盘加载到内存&#xff0c;此时发生一次IO&#xff0c;在内存中用二分查找确定29在17和35之间&#xff0c;锁定磁盘块1的P2指针&#xff0c;内存时间因为非常短&#xff08;相比磁盘的IO&#xff09;可以忽略不计&#xff0c;通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存&#xff0c;发生第二次IO&#xff0c;29在26和30之间&#xff0c;锁定磁盘块3的P2指针&#xff0c;通过指针加载磁盘块8到内存&#xff0c;发生第三次IO&#xff0c;同时内存中做二分查找找到29&#xff0c;结束查询&#xff0c;总计三次IO。真实的情况是&#xff0c;3层的b&#43;树可以表示上百万的数据&#xff0c;如果上百万的数据查找只需要三次IO&#xff0c;性能提高将是巨大的&#xff0c;如果没有索引&#xff0c;每个数据项都要发生一次IO&#xff0c;那么总共需要百万次的IO&#xff0c;显然成本非常非常高。

###b&#43;树性质
1.索引字段要尽量的小&#xff1a;通过上面的分析&#xff0c;我们知道IO次数取决于b&#43;数的高度h&#xff0c;假设当前数据表的数据为N&#xff0c;每个磁盘块的数据项的数量是m&#xff0c;则有h&#61;㏒(m&#43;1)N&#xff0c;当数据量N一定的情况下&#xff0c;m越大&#xff0c;h越小&#xff1b;而m &#61; 磁盘块的大小 / 数据项的大小&#xff0c;磁盘块的大小也就是一个数据页的大小&#xff0c;是固定的&#xff0c;如果数据项占的空间越小&#xff0c;数据项的数量越多&#xff0c;树的高度越低。这就是为什么每个数据项&#xff0c;即索引字段要尽量的小&#xff0c;比如int占4字节&#xff0c;要比bigint8字节少一半。这也是为什么b&#43;树要求把真实的数据放到叶子节点而不是内层节点&#xff0c;一旦放到内层节点&#xff0c;磁盘块的数据项会大幅度下降&#xff0c;导致树增高。当数据项等于1时将会退化成线性表。
2.索引的最左匹配特性&#xff1a;当b&#43;树的数据项是复合的数据结构&#xff0c;比如(name,age,sex)的时候&#xff0c;b&#43;数是按照从左到右的顺序来建立搜索树的&#xff0c;比如当(张三,20,F)这样的数据来检索的时候&#xff0c;b&#43;树会优先比较name来确定下一步的所搜方向&#xff0c;如果name相同再依次比较age和sex&#xff0c;最后得到检索的数据&#xff1b;但当(20,F)这样的没有name的数据来的时候&#xff0c;b&#43;树就不知道下一步该查哪个节点&#xff0c;因为建立搜索树的时候name就是第一个比较因子&#xff0c;必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时&#xff0c;b&#43;树可以用name来指定搜索方向&#xff0c;但下一个字段age的缺失&#xff0c;所以只能把名字等于张三的数据都找到&#xff0c;然后再匹配性别是F的数据了&#xff0c; 这个是非常重要的性质&#xff0c;即索引的最左匹配特性。

四 聚集索引与辅助索引

在数据库中&#xff0c;B&#43;树的高度一般都在2~4层&#xff0c;这也就是说查找某一个键值的行记录时最多只需要2到4次IO&#xff0c;这倒不错。因为当前一般的机械硬盘每秒至少可以做100次IO&#xff0c;2~4次的IO意味着查询时间只需要0.02~0.04秒。

数据库中的B&#43;树索引可以分为聚集索引&#xff08;clustered index&#xff09;和辅助索引&#xff08;secondary index&#xff09;&#xff0c;

聚集索引与辅助索引相同的是&#xff1a;不管是聚集索引还是辅助索引&#xff0c;其内部都是B&#43;树的形式&#xff0c;即高度是平衡的&#xff0c;叶子结点存放着所有的数据。

聚集索引与辅助索引不同的是&#xff1a;叶子结点存放的是否是一整行的信息

1、聚集索引

#InnoDB存储引擎表示索引组织表&#xff0c;即表中数据按照主键顺序存放。而聚集索引&#xff08;clustered index&#xff09;就是按照每张表的主键构造一棵B&#43;树&#xff0c;
同时叶子结点存放的即为整张表的行记录数据&#xff0c;也将聚集索引的叶子结点称为数据页。聚集索引的这个特性决定了索引组织表中数据也是索引的一部分。
同B&#43;树数据结构一样&#xff0c;每个数据页都通过一个双向链表来进行链接。
#如果未定义主键&#xff0c;MySQL取第一个唯一索引&#xff08;unique&#xff09;而且只含非空列&#xff08;NOT NULL&#xff09;作为主键&#xff0c;InnoDB使用它作为聚簇索引。#如果没有这样的列&#xff0c;InnoDB就自己产生一个这样的ID值&#xff0c;它有六个字节&#xff0c;而且是隐藏的&#xff0c;使其作为聚簇索引。#由于实际的数据页只能按照一棵B&#43;树进行排序&#xff0c;因此每张表只能拥有一个聚集索引。在多少情况下&#xff0c;查询优化器倾向于采用聚集索引。
因为聚集索引能够在B&#43;树索引的叶子节点上直接找到数据。此外由于定义了数据的逻辑顺序&#xff0c;聚集索引能够特别快地访问针对范围值得查询。

聚集索引的好处之一&#xff1a;它对主键的排序查找和范围查找速度非常快&#xff0c;叶子节点的数据就是用户所要查询的数据。如用户需要查找一张表&#xff0c;查询最后的10位用户信息&#xff0c;由于B&#43;树索引是双向链表&#xff0c;所以用户可以快速找到最后一个数据页&#xff0c;并取出10条记录

#参照第六小结测试索引的准备阶段来创建出表s1
mysql> desc s1; #最开始没有主键
&#43;--------&#43;-------------&#43;------&#43;-----&#43;---------&#43;-------&#43;
| Field | Type | Null | Key | Default | Extra |
&#43;--------&#43;-------------&#43;------&#43;-----&#43;---------&#43;-------&#43;
| id | int(11) | NO | | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | char(6) | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
&#43;--------&#43;-------------&#43;------&#43;-----&#43;---------&#43;-------&#43;
4 rows in set (0.00 sec)mysql> explain select * from s1 order by id desc limit 10; #Using filesort&#xff0c;需要二次排序
&#43;----&#43;-------------&#43;-------&#43;------------&#43;------&#43;---------------&#43;------&#43;---------&#43;------&#43;---------&#43;----------&#43;----------------&#43;
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;------&#43;---------------&#43;------&#43;---------&#43;------&#43;---------&#43;----------&#43;----------------&#43;
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 2633472 | 100.00 | Using filesort |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;------&#43;---------------&#43;------&#43;---------&#43;------&#43;---------&#43;----------&#43;----------------&#43;
1 row in set, 1 warning (0.11 sec)mysql> alter table s1 add primary key(id); #添加主键
Query OK, 0 rows affected (13.37 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql
> explain select * from s1 order by id desc limit 10; #基于主键的聚集索引在创建完毕后就已经完成了排序&#xff0c;无需二次排序
&#43;----&#43;-------------&#43;-------&#43;------------&#43;-------&#43;---------------&#43;---------&#43;---------&#43;------&#43;------&#43;----------&#43;-------&#43;
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;-------&#43;---------------&#43;---------&#43;---------&#43;------&#43;------&#43;----------&#43;-------&#43;
| 1 | SIMPLE | s1 | NULL | index | NULL | PRIMARY | 4 | NULL | 10 | 100.00 | NULL |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;-------&#43;---------------&#43;---------&#43;---------&#43;------&#43;------&#43;----------&#43;-------&#43;
1 row in set, 1 warning (0.04 sec)

聚集索引的好处之二&#xff1a;范围查询&#xff08;range query&#xff09;&#xff0c;即如果要查找主键某一范围内的数据&#xff0c;通过叶子节点的上层中间节点就可以得到页的范围&#xff0c;之后直接读取数据页即可

 

转:https://www.cnblogs.com/wangkun122/p/8047582.html



推荐阅读
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
  • 如何优化MySQL数据库性能以提升查询效率和系统稳定性 ... [详细]
  • 通过使用 `pandas` 库中的 `scatter_matrix` 函数,可以有效地绘制出多个特征之间的两两关系。该函数不仅能够生成散点图矩阵,还能通过参数如 `frame`、`alpha`、`c`、`figsize` 和 `ax` 等进行自定义设置,以满足不同的可视化需求。此外,`diagonal` 参数允许用户选择对角线上的图表类型,例如直方图或密度图,从而提供更多的数据洞察。 ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • 在配置Nginx的SSL证书后,虽然HTTPS访问能够正常工作,但HTTP请求却会遇到400错误。本文详细解析了这一问题,并提供了Nginx配置的具体示例。此外,还深入探讨了DNS服务器证书、SSL证书的申请与安装流程,以及域名注册、查询方法和CDN加速技术的应用,帮助读者全面了解相关技术细节。 ... [详细]
  • 在List和Set集合中存储Object类型的数据元素 ... [详细]
  • 基于Linux系统的Kickstart自动化服务器部署方案
    本文针对企业需求,提出了一种基于Linux系统的Kickstart自动化服务器部署方案。该方案旨在通过无盘批量安装操作系统,提高企业IT基础设施的部署效率。Kickstart是一种利用Anaconda工具实现服务器自动化安装的技术,能够显著简化和加速操作系统的安装过程。通过详细的实施规划,本文介绍了Kickstart的工作原理及其在实际部署中的应用,为企业提供了高效的自动化部署解决方案。 ... [详细]
  • 在iOS开发中,基于HTTPS协议的安全网络请求实现至关重要。HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer)是一种旨在提供安全通信的HTTP扩展,通过SSL/TLS加密技术确保数据传输的安全性和隐私性。本文将详细介绍如何在iOS应用中实现安全的HTTPS网络请求,包括证书验证、SSL握手过程以及常见安全问题的解决方法。 ... [详细]
  • 经过两天的努力,终于成功解决了半平面交模板题POJ3335的问题。原来是在`OnLeft`函数中漏掉了关键的等于号。通过这次训练,不仅加深了对半平面交算法的理解,还提升了调试和代码实现的能力。未来将继续深入研究计算几何的其他核心问题,进一步巩固和拓展相关知识。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 本文深入探讨了佩尔方程 \( x^2 - dy^2 = 1 \) 的递推关系式。通过构造特定的矩阵并利用矩阵快速幂的方法,可以高效地计算出该方程的第 k 组解。此外,文章还详细分析了递推关系式的数学背景及其在数论中的应用,为相关研究提供了坚实的理论基础。 ... [详细]
  • Python全局解释器锁(GIL)机制详解
    在Python中,线程是操作系统级别的原生线程。为了确保多线程环境下的内存安全,Python虚拟机引入了全局解释器锁(Global Interpreter Lock,简称GIL)。GIL是一种互斥锁,用于保护对解释器状态的访问,防止多个线程同时执行字节码。尽管GIL有助于简化内存管理,但它也限制了多核处理器上多线程程序的并行性能。本文将深入探讨GIL的工作原理及其对Python多线程编程的影响。 ... [详细]
  • 在洛谷 P1344 的坏牛奶追踪问题中,第一问要求计算最小割,而第二问则需要找到割边数量最少的最小割。通过为每条边附加一个单位权值,可以在求解最小割时优先选择边数较少的方案,从而同时解决两个问题。这种策略不仅简化了问题的求解过程,还确保了结果的最优性。 ... [详细]
author-avatar
chunjhyy6668787
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有