特种兵数据库手抄

Java特种兵数据库部分笔记(一)

6.2 从开发人员的角度看数据库原理

         小伙伴们看了上一节的内容是否会想一想:我们是否需要向DBA那样子擅长DB的知识呢?当然不是,相互之间是一种合作关系,但不能在此昂胡之间隔着一堵墙甚至于隔行,相互之间是需要交流与沟通的,在交流与沟通的过程中相互学习并在许多问题上达成共识。

         开发人员到底需要学习那些方面的数据库的知识呢?胖哥认为数据库的基本原理、索引原理、常见的优化手段等是开发人员需要掌握的,这些内容对于卡发开发者来讲应该并不算复杂,而且也花不了太多的时间就可以学习清楚,在解决大多数日常问题的基础上,自己也得到了一定的能力的提升。

         在本节就用一些通用的数据库的特征来进行说明,这些内容大多是思想和方法上的,在这个基础上,大家如果想要学习一种具体的数据库则会更加轻松一点,至少看待数据库的角度应该是有所改变的。

6.2.1 实例与存储

         数据库不仅仅拥有存储,还应当有为外界提供数据服务的程序,这个程序对存储的细节进行封装,对外提供简单的服务,通常把他叫做实例,有了存储与实例的组合,才成为真正的数据库。

         部分数据路的定义是实例与DB的组合,这个时候DB指的就是存储。大家不用过分纠结这些概念,否则就会将自己的思维局限在某一种数据库上,无法跳出这个圈子,有了自己的理解就无需过分关注到底用的是什么名词。存储本身可简单的理解为存储设备上的一套文件系统,存储设备可能是一块硬盘,一组磁盘组成的磁盘阵列(RAID)、一个专门的存储服务设备,通常情况写程序通过os提供的API对存储设备进行读写,当然某些数据库系统也可以跳过os直接操作裸设备。

         反过来讲,如果磁盘上存储的数据仅仅是一组文件,而没有像数据库那样提供各种文件的管理功能,就不应该算是数据库(因为数据库应当有对数据进行操作的功能)。要满足一个数据库的要求,需要有整套程序对文件的分隔,数据的格式进行统一的管理,并在这个基础上提供通用的数据操作API才能叫做数据库,这就是建立在存储基础上的程序实例,简称实例。

         说明实例与存储来组成数据库,首先是要让大家形象了解数据库是什么样的一种形象,胖哥认为任何一种数据库都脱离不开这个基本道理。

         了解到这里,可以将思维再打开一点——实例与存储既然是分开的,那么他们并不用一一对应起来,但是如果不是一一对应的关系,就会有许多实现上的去呗,区别是各个数据厂商对数据库的理解会有所不同,数据库的体系架构自然会不同,通常来讲,同一个数据的多套存储,是用于冗余备份容灾的。一套存储对应到多套实例是为了提升整体对外的负载能力,达到高可用性。

         数据库实例启动后代表数据库已经开始运行,并提供对外服务,数据库使用者需要了解账户与数据库之间的关系,下面简单的介绍一下:

         部分数据库可能会强化数据库的概念,数据库一个对外服务的整体,一个数据库的建立包含了存储、实例的建立。一台主机也可以安装多个库。如果库与存储是一对一的关系,那么库名字与实例的名字通常就是一致的,如果是集群则通常会有一个服务名的概念的存在。这类数据库除了有超级账户之外,每个账户登录后都会有自己的默认空间和访问权限。如果要访问到其他账户的信息,则必须得到其他账户或者超级用户的授权才可以访问到。

         有的数据库则会弱化数据库的概念,数据库安装后仅仅是一个空的数据库实例,也会有超级账户,当在实例上穿件数据库的时候,通常会为创建的数据库分配一个目录,此时的数据库的概念很弱,他仅仅是存在于实体上的逻辑单位。在这样的数据库上,登录用户不许奥与具体的某个库绑定起来,即没有所谓的私有区域,只有授权访问的数据库列表。账户登录时可以指定库名登录,那么登陆后就直接进入了某个库下进行了操作,也可以不指定库名,在拥有的权限的库之间来回切换。

6.2.2 数据库的基本原理

本小节胖哥就自己的理解来谈谈数据库的基本原理,从开大这的角度看看数据库需要做什么样子的事情。前面谈到了存储与实例,实例是程序,用于将物理上的关系转换成逻辑上的关系,将复杂的问题简单化。下面我们首先来谈谈物理与逻辑上的内容:

(1)      块与页

谈到数据库的物理存储,就从最小的数据操作开始,如果我们自己写程序对文件系系统进行读写操作,则可能为了让程序简单,以行为单位进行读取,或者通过随机读写的方式定位后读取一段数据,数据库的实例也是程序,也有类似的处理方式,他要处理数据不能再磁盘上做,肯定在程序中做,在程序中做的话自然要将数据加载到程序空间所在的内存中。

数据库通常不会以行为单位来加载数据,因为行的大小粒度不容易控制也不利于调度管理,例如,很多是够每行数据都是以百字节为单位的,甚至更低,如果发生一次io只读取这么一点数据。那么io就太频繁了、很多时候我们虚妄程序读取这一行的数据的时候,在读取连续的许多行数据到内存中(由于当前行接下来的几行数据被访问到的概率通常很高,那么这样就可以提高内存命中率),加载到内存后有一个大进程来管理这些板块。

在数据库中通常对数据做物理大小的划分,以kb为大小的基本单位来存储,而不是以行的多少位单位来进行存储,单位的名称有的数据库叫做块,有的数据库成为页。为了统一,在以后我们将统一称之为块。

这样一来每个块通常会存储许多行数据,数据库为了记住每个快,通常会给每个快分配一个标志符,这个标识符不一定使卫衣的,不过他可能与某些更高抽象层次的标识符数组组成一个卫衣的标识符。由于块内部存放多条数据,为了表示每条数据,块内部的每条数据通常都会有自己的行号。

在不同的应用中,可能会设置不同大小的快,希望它存储相对较多的数据,又便于库存储粒度的管理。

物理上的磁盘并不会单独生成一个快,也没有块的这个概念,“块”本身也是将文件系统的某个数据范围抽象出来的逻辑盖面,由于数据库对存储的输入输出控制有自己规约好的一套系统,因此数据库实例就可以识别出具体的块

什么是数据库对存储内容的规约呢?数据库有数据字典来记录数据库各种各样的信息,他们会记录下每个快在文件系统中的偏移量,相当于记住了他的位置。找到了偏移量就等价于找到了快的启示位置,再从这个起始位置开始读取等同于块大小的区域就成功的读取了这个快所存放的内容。这种文件操作方式类似于java用随机读写来访问文件。

(2)      多个连续块

一个表要存储许多数据,随着数据的增加肯定不止一个块来存放也就是需要很多这样的块来存放数据,这些块存放的位置或许会在一定程度上影响性能。

通常存储设备的效率是最低的,数据库性能的巨大障碍之一就是磁盘存储,而磁盘存储效率低主要是滴在磁盘的iops上面,及每秒可以发生的io操作次数太低(不考虑固态硬盘),其实每次io操作从磁盘上读取连续的1kb/1Mb的数据的时间实际上是差不多的。换句话说,慢的主要原因是一个块只有一个磁头,对一块因公安的io请求通常都会被串行化,每个io请求都需要通过摆动抬头来进行磁道定位,再在该磁道内部通过磁盘旋转等待数据的开始位置,当数据的开始位置找到之后,便开始真正的读取数据,读取速度是非诚块的

根据上述理论,我们希望数据库每次读取的不仅仅是1kb 2kb的数据,很多时候希望能够读取更多的数据,此时将多个块的数据连续放在一起组成一组数据,这样在李湘情况下可以成倍提升存储设备的性能。

我们将多个块一起读的做法叫顺序度,顺序度是相当于随机读而言的,也就是每次读取的量会更待一些,但是在物理上并不存在每次读取100M的数据,即时应用程序是这样的,物理上也会拆分成多个小的io来调度。

将多个快组成一个分组之后,这个分组在一些数据库上叫做extends,他被认为在文件系统这个级别是连续存储的,理论上在磁盘上是相对连粗的一块空间,但是不绝对保证是这样的,就想一个大文件存放在磁盘上时,也会在磁盘的碎片的空隙中寻找位置一样。换句话说,这种连续也是逻辑的,但是只要做好相应的碎片管理,在很多时候就认为它确实是连续的。我们希望读写操作都是顺粗的,不过在许多实际场景中往往不是这样的,由于内存空间的限制,数据库常常会以类似于LRU的算法来管理块,让,有些访问过多的块留在内存,或者让访问少的块从内存中释放出去。如果一些连续的数据块加载后,这些连续块中的部分快没有被访问,那么这部分块就可能会在LRU的调度下写回磁盘,这些连续记在的顺序快之间存在空隙,而当再次加载这样的块的时候,数据库通常不会再一次加载这些快,而是加载空隙中所没有加载的这些块,而当连续块中出现多个空隙时,通常叫发货时能多次io操作来读取这些空隙快,这样书序草做就变成了顺序度,最坏的情况就是在一大堆的连续块空隙快与没内存中catch交替,还会有更大出现。

有时候数据库的分布式不容易被确定的,但是一些索引的顺序是可以被确定的, 因为索引本身是有序的,尤其是自动增长列这样的索引,里这类数据最近的数据通常是访问最热的,那么被连续加载的概率是很好的,如果将他三列,此时就可能会稀疏分布在许多快上面。

另外,连续读取的粒度并非仅仅收到磁盘的控制,通常数据库也会有参数来控制一次连续读的块数。

在实际的数据库中,还会有更大的空间,例如某些数据库会用多个extends来组成segments。一个表对象可以划分到多个segments中,这样来实现分区别独立管理。

(3)      修改表

试想一下,如果一个表中的每个数据库中都存储了数据,此时要向一个表中增加一个字段,而且要马上向这个字段中写值,那么会发生什么事情呢?某些数据库会实现在写入每个块时给他们预留少部分空间,也就是每个块都不会写满,以便于在添加字段的时候可以使用,但是这并不能确保永远够用(例如增大一个超级大的字段)。如果空间不够用,就会将一行数据的某个部分放在另一个块中,这两个块可能此时相隔很远,在访问数据库时,以前只需要一次io就可以得到的数据,现在需要多次io才可以。

遇到这类问题的时候,虽然可以通过压缩,整理等方式来处理,但是这个过程予予需要移动相关的数据,因此会小号数据库的性能,所以作为程序设计者,千万不要认为对线上的数据库增加字段是一件很随意的事情。

某些开源数据库没有数据字典的概念,大多数描述信息都在在以表为单位的文件头部完成的,当表的结构发生修改的时候,通常会创建一个新表,并将原表中的所有数据全部拷贝到新表中,在拷贝的过程中为了保证数据的一致性通常会发生锁表的情况。对于小表,这样的操作可能还比较畅快,但是对于大表,这样的操作将会十分恐怖,外界可能长时间无法访问这个表,因此对于大数据的存储,通常会采用所谓的“分库分表”策略。

(4)      删除表

删除表操作对于使用者来讲很简单,但是对于数据库可能需要做一番复杂的处理,因为表中可能会有大量的数据需要清理,一些商业数据库还会考虑表被误删需要恢复的问题。

删除表的时候清理数据不能像delete操作那样逐条删除,通常是基于数据库的体系结构去清理的,耨写数据库在内存中基于表的名称hash分布数据,这样就可以通过表名称快速定位到该表在内存中的数据,那么清理动作应该会很快。不过耨写开园数据库的存储方式并非这样,它在内存中可能是一种线性结构来存储的,这是就可能发生w问题了。即使在一个数据库中删除一个空表,也可能会导致系统延迟很大,为何,请看下面的解释。

所有的数据库都存在内存命中率的问题,如果内存命中自然就不用访问效率低上百倍的磁盘了,因为对于数据库来讲,我们通常会给他配置较大的内存来达到很高的命中率。这意味着,如果要找到一个表在内存中cache的数据有可能要扫描整个数据区域。有些时候还要不仅仅扫描一次,例如mysql的innodb buffer若设置非常大,那么在连续删除表的时候就可能导致数据库系统性能下降,即时删除整个空表也会导致系统的延迟飙高。

删除某些数据库中的表,为了方位误删,会在默认的处理删除的动作的时候只是修改一个名字并将修改后的表名字与原来的表的名字做一个简单的映射,溶蚀也改变其元数据的状态,在默认的情况下我们看不见他(如同回收站一样)。但是他依然占用磁盘空间,数据一点都不少存在,这样的删除操作自然是瞬间完成的,如果发现删错表了,通过一个简单的语句就可以瞬间恢复,如果想要直接在物理上删除表或者清空回收站,就需要数据库提供特定的操作语法来完成。

(5)一个sql的运行可能会经历的步骤

当一个sql请求访问到数据库的时候,他通常会经历sql解析的过程,这个解析过程就是将sql语句解析为数据库操作。换句话说,sql是人类约定语法后看的懂的信息,因为人类学会了如何解析sql语句,但是传达到机器后机器也需要认识sql语句,他需要解析sql语句后才知道到底需要什么比如sq语句在做读写操作,对那些表做操作,表与表之间的关系是什么,条件是什么等

一些数据库为了提高并发的访问,让数据库运行的更快,会将这个解析过程缓存起来,因为它认为这样的系统通常sql语句的服用概率会很高,当同样的sql语句再次发送过来的时候,就会取出已经解析好的结果直接运行,通常将这个过程叫做软解析,或者说他是假的解析,软加息在并发系统中十分有效果,在这类数据库中其性能可以成指针数级提升,反过来讲,在这类数据库中最不希望看到的就是硬sql(即参数是通过值平凑出来的而不是通过预编译出来的),因为所有的sql对于服务器端都被认为是不一样的,sql的复用的概率很低,由于存储这些sql的空间也是有限的,它会同样利用类似lru的算法来管理内存区域,在高并发的系统中,可能会由于存在有大量拼接参数的sql导致一次性的垃圾sql太多,这样有可能会将一些原本应该留在内存的sql替换出内存。

补充:软解析机制在偶然查了数据库上体现的邻里禁止,但并不代表这种机制在所有的数据库上都能优化整体性能。例如在分布式的系统数据库上,硬解析的成本将被打扫到多太服务器上,而sql语句的解析若不需要做各种优化分析和cache。其开销通常在微妙级别,这个时间对于整体系统来京几乎可以忽略,另外,予予数据库表不断拆分,表名称会增多,要达到较高的命中率就需要更大的内存,这种思路是与分布式的解决思路的道路背道而驰的,并且用如此大的内存去解决一个微妙级别的问题显然是不值得的。

部分数据库提供了对于某些内存区域的优先级管理机制,可以指定或智能的计算出某些数据是加载后机会永远不会卸载的,某些数据区域是加载使用后可能会被立即卸载或内存不够的时候首先被卸载的,某些数据区域则是采用专用的LRU的管理方法。

从写程序的角度来讲,sql解析的开销其实并不是那么恐怖,因为它是纯cpu操作,在高并发下坠在某些数据库上体现出优势。

解析完成后便知道sql到底要做什么了,以一个查询语句为例子,在经过解析后便知道了查询表,以及多个表之间的关联条件,为了知道这样的表是否存在,以及所查询的字段是否存在,就必须要先查询数据字典。

数据字典就适用于保存数据库的一些描述信息,通常也是以表的方式存储的,由于一个数据库本身的对象通。

常不会太多,而且他的更新速度肯定不会像更新数据那么频繁,所以通常将他加载到内存中提供访问。

数据库访问自身的元数据时通常是可以通过抽象层次相对较低的api完成的,但是也不排除某些数据也是用sql完成的,总的来说,上文中所提到的数据字典加载病是不是说还要查询一次数据库后台。

确保表和属性都存在后,数据库就要开始计划如何读取表中的数据并对数据进行处理,单表操作的时候会考虑是否走索引,多个表操作的时候会用join的方式或者union的方式,排序有排序方法,分组有分组策略,他们始终沿着提提条路径在执行数据看,数据库在执行语句钱会计算出这条执行路径,也就是所谓的执行计划。

 

所以在很多时候,定位一个sql的性能如何,关键的做法是先看执行计划,当执行计划没有问题的时候可以不去增加索引,当执行计划出现问题的时候,就要看执行计划中的那些路径是不是我们期望的方式。那么此时就要考虑合适的办法来解决,例如如何修改sql逻辑,调整索引或者某些数据库指定的方法来实现。关于执行计划,下面举哥简单的例子来说明他的重要性。

要的哦到一个良好的执行计划是非常复杂的,它要参考sql的join方式,原有表的大小,索引的建立等方法来综合计算得到执行计划的结论。

对于小表,访问量低的表,无所谓执行计划的问题,而对于达标,访问量高的表,执行计划就显得十分重要,所以很多时候问了让数据库有更好的执行计划,会提供一些统计值或者告诉数据库下一步举题应该怎么执行。如果没有这些功能,而单纯的吧数据库当成一个存储引擎,就只能自己写代码来完成这一切活动了。

当一个sql执行计划指定完成之后,就按照这个计划进行读写、合并数据、排序数据等操作,这个过程是需要数据库分配内存或者磁盘资源来处理的,这种资源分诶在不同的数据库上会有不同的实现。例如有的数据库,在用户连接创建的时候就会分配一个及mb的用户空间,用于满足用户绝大部分的数据请求都可以在内存中实现数据的和并与排序操作,同时将不同的用户的资源进行隔离,但是如果在计算的过程中设计大量yogurt数据的操作,这些数据库则会尝试选择一块额外的临时龙剑来做一些排序join的操作,同时需要注意的是这类数据库的创建连接的开销会相当大一些,某些数据库在分配连接时仅仅是分一个套接字,可能会有一个饷银的线程来对应,但是不会单独为链接分配空间,在实际运行的过程中,根据链接需要使用的资源再去分配空间。

数据库实际读取数据时候,其内部可能还会经历多个步骤,在某些数据库上可能会使用单线程来提供数据服务,因此他就可能会成为资源瓶颈,可能会像cpu一样基于时间片为外部提供数据的服务,或者基于行为基本党委对外服务,也可能服务完成一个请求的所有数据后才为下一个请求服务,但是这种服务不经不是cpu服务,所以没有cpu的速度那么快速,他说操作的可能是计算机中最慢的io部件。当遇上大连的请求时候,如果以太细的粒度为外部的虚火请求进行轮训服务,那么许多大的任务就可能在并发的系统中很难得到返回值,在并发小的时候可能体现不出来。如果以fifo的方式来处理并发请求,可能会因为一个大请求的时间过长影响后面服务的执行。

基于行为单位的服务方式可以改善的点就是粒度的问题,也就是在上面两种极端都想中间走一点,也许可以让其返回的行并不仅仅是一行,而是多行,这种粒度可以认为的控制甚至只能计算出来。

程序员应当知道,在这样的数据库中,之所以不在业务运营的高峰期做大量的操作,尤其是在主库上做这样的操作,是因为字这种模式下无论怎么操作都会影响正常的运行。

但是在某些数据库中是允许的,因为他有一套体系架构来隔离资源,更为重要的是,这样的体系架构可以支持更大的存储设备,这些存储设备以及他本身的架构提供了这样的基础,单是他同时带来的是这个数据库软甲的复杂性以及伸缩能力。

(5)      加锁

数据库中有各种各样的所机制,在规范的数据库定义中也就有各种锁的定义。

当访问某些数据库的表的时候,不论是读操作,还是写操作,都会在数据字典上加锁,以保证在访问此表的时候他不会被删掉,表结构也不会被修改,我们可以认为这就是共享锁,这把锁并不是放在数据上的,所有的数据操作依然可以并发的进行。

当发生数据的写操作 更新操作的时候,这就相当于锁定了某些书库,这种锁通常是基于行的,也是排他的,即不允许在这个区域同时发生两个写操作,但是只读操作是允许的,与第5 张的锁机制对比,这更加像是读写锁。

这样就会产生疑问,当发生读操作的时候,数据库正在进行写操作,那么读操作获取到的数据可能就不是最新的,这对于数据库来京是正确的结论,因为数据库通常认为你要读取的数据是发起sql查找时间点的数据,如果在读物的过程中发生修改,即时还没有读取到修改数据的行,也不应该将修改后的数据返回给客户端,这在数据库中会存在一个时间戳或者版本号的概念来保证对应的数据。

对于某些数据库锁住的行可能不仅仅是where调价过来的行,如果他没有索引,则可能会锁住所有的行,当where条件中的部分字段有索引,部分字段没有索引的时候,锁住的行有些时候仅仅是有索引的条件过滤出来的行而不是最终刚过滤出来的行。Eg,where a=? and b=? 其中a走了索引,而b没有走索引,此时锁住的行就可能会包含所有条件a过滤出来的数据,而不是用在条件b过滤掉以后再加所。

部分数据库为了加快锁的速度,会以块为单位加锁,在块的头部会半酣这个快的内部的行信息,对于每一行来京会有单独的1个bit来标识自己是都已经被加锁,多行数据就用多个bit位来表示,他只要将要加锁的行对应的bit位变成1,余该快中本身的锁bit位按位求或即可将这个快中相应的行家一次锁,这样一来,一个块中多行的数据就可以一次性加锁。

不过,数据库的锁很多时候也无法完全保证所有的一致性,即佳作即时再快也会有一个过程,尤其是对一个达标做没有where条件的更新的时候需要一个相对较长的过程,它通常会按照块的顺序进行加锁,这样的sql加锁的过程可能会出现一些问题,要保证对大表的批量修改需要一个其他的方式来保证一致性。

Eg

第一个操作要求锁住整个表,第二个操作要求锁住表的最后一行,可能第一个开始了,第二个几乎很快就开始,这样,第一个任务还没有完成,第二个任务就已经开始了,这是不科学的,这相当于第一个任务要等第二个任务完成之后才可以进行了。

但是如果严格的先到先得的话,就偏向于串行化了,这样就可能会因为一个大人物的请求而导致整个系统的延时。也许将这个耦合放的开一点,会让问题便的简单,这种先后的瞬间问题,可以由业务层面来保证。

如何保证:以金额修改为例手先不能自sql语句中指定结果值如果指定结果值,就可能会出现覆盖问题,后提交的sql因为先执行,而被仙女提交的sql后执行所覆盖,这是不合理IDE。我么可以采用的是相对金额,可以用类似于cas的方式来根据修改数据的版本号来提交要修改的数据行,即再修改的时候带上读取时候的版本号,若版本号一直,则修改相对金额,若版本号发生了变化,则不会修改任何行,此时可以用重试或者达标即的方式来完成接下啦的工作。

数据库的行所也是技术层面提到的东西,行锁的粒度应该被打散这使用。

数据库的乐观锁。用版本号和返回值控制,多个写只有一个写会成功。但是如果wher中没有索引,或者索引跟加锁字段不在同一个字段,这样也没有办法保证乐观锁的效果。

锁的粒度是跟着索引走的,而不是跟着结果走的。

Myisam的锁是表级别的。即时一个查询游标没有关闭 也会影响修改曹组的进行。这个引擎是mysql数据库的标配。

(6)      提交

在数据库中发起commit的操作的时候,数据库通常会保证数据肯定会存在,但是未必会保证在commity的时候会吧脏数据写入到存储设备上。数据库宕机数据没有丢掉的原因是,数据库在commit之前,会将日志写入磁盘中,指着日志的写操作从程序的角度来讲被认为是顺序的,许多高并发额数据写操作需要找到对应的块、行才能写入,而且每一个写入一点点数据的时候,这种写入通常是随机写入的。

另外,数据库通常会在内存中分配一个日志缓冲区,这个缓冲区是有大小限制的,即时不做commit操作,在一段时间后或者日志缓冲去达到一定的容量的时候也会发生存盘的操作,因此,在大多数的情况下,发生commit操作时候,并不会因为事务本身的大小导致提交操作的时间长短,如果真的发生这样的情况,则需要考虑是否是其他的因为导致的。

通过日志回复的基本条件是有一个版本号的概念。版本号对应时间点,数据的版本号与日志的版本号不一致提示错误后继续操作或根据日志同步为一样的版本号。

高并发的时候可以考虑没个3s同步一下数据。来避免commit操作的过于频繁所导致的日志写操作也过于频繁。然后一次性写日志中。

(7)      回滚

Redo 重做数据丢了要重新补上

Undo 回复  回复到前面的版本

重做的反向机制 日志方式提供支持(日子查询功能、日志解析功能);记录的版本号提供支持。

(8)      版本号

6.2.3 索引的基本原理

索引:提升查找性能、降低写性能,是数据,需要村相互,存储原理与数据类似(数据块或者数据页)。

         有pk表的表默认为是索引组织表。

B+树的概念;

索引的存储:

         1.索引存储对应字段的内容,通过标识符(物理位置、主键值)与原表链接起来。

         2.索引与数据是分开存储的(索引组织表除外)。

         3.单独我索引存储分配空间,使得索引与数据的存储和管理相分离,这样一来,可以利用磁盘达到局部优化的墓地。

         4.索引是有序的。

查找数据分为两个过程:索引查找标识符-à通过标识符找到原表的位置提取数据【回表】。(查询小表不走索引会更快)、(如果查询的字段都在都引种就不用回表了)。

表的修改对索引的影响:没有索引的话,摘到对应的要修改的数据难;有索引的话,还要修改索引。

向表中写入数据:

         1.如果数据很少,只有几十条这样子,索引只有一个块-叶子块

           访问的时候不走作引可能会更快。

         2.数据块多的时候涉及到“分裂”。

                   叶子块之间有顺序;管理块之间存储

索引范围。自动增长的分裂可以分裂

出空块。一般两级可以代表大多数任务,

这样的索引快经常被放到内存中

 

 

 

 

 

 

 

 

 

 

 

 

3.sql请求到达数据库à走索引吗?

【Y】 树根à二分查找下一步(每次最多一次io)à…à叶子块à实际位置à回表

                   4.当sql需要做统计操作的时候(count)双向链表

                            计划:索引à第一个叶子块à扫描à…à最后一个叶子块à计算

                            大表走索引有优势,小表可能索引比主键还小,还不如直接读表。

                            现实中where大部分有条件。

                            超大的表,由于索引叶子块双向链表,可以双向遍历。但是

                                     叶子块数多àcount慢===》大表不建议count

                   5.max,min 有where吗?

                    【Y】正常的索引找最大值

                    【N】找第一个叶子块或最后一个叶子块。,

                   6.分页=where+orderby+行号=分页的范围

                   【普通sql分页】索引值找范围à回表

                   【索引上翻页】 找到物理地址 查询原表

                   【如果没有物理地理】用主键代替à索引要挂在主键

【页数非常多】前10-20或后10-20被翻阅的次数多à前翻还是后翻àorderby?desc

7.复合索引(多个字段)c1、c2

         索引有序条件是前缀条件à后缀是无序的à全表扫面/走索引分散到多个板块

         跳跃式的找叶子块里面的数据。

8.like 与复合索引类似

·前缀-缩小范围;后缀-全表扫描

9.in/or

         离散在多个快当中每个条件单独寻找àin的条件太多自动全表扫描

         In的效果看表与表之间的驱动关系,大表?走理想中的索引。外部插叙做驱动表很恐怖

10.唯一性索引uk pk

         在进行等值查询、少量的in查询的时候有区别 找到一条数据就停下来。

11压缩

压缩重复的数据 同一个索引值只存储一份,保存多个地址

12 位图索引

 缺陷-锁粒度很大 同一个位图的数据操作都会被锁住

6.2.4 数据库主从基本原理

对于程序员来讲,可能不需要知道太多的数据库备份的知识,以及操作方法和古战处理方式,但是可以了解一下备份的基本原理,因为备份也并不是没有开销,也并不是可以无限利用,它同样可能会在一定程度上影响总体的架构以及性能。

备份由代码完成,不同的备份有不同的方式。

à逻辑模式 主库执行啥;从库也干啥 粒度细,易识别,问-生成的sql多

  从库存在压力:从库的写是单线程来完成的。不论主库有在搞的并发压力,从库都只有一个线程在发生写操作,不断的进行循环写,在这个过程中可以减少大量的系统资源征用问题。问题—主库写的太快,从库跟不上à解决并行复制 相当于开了并发 压力变大

à物理模式 基于修改的数据库复制 提取比从库版本号高的进行复制  不用sql以及其调度

问题从库对外访问好麻烦的偶

6.2.5 我们经常相信的那些经验

6.3 从程序员的角度看数据库有句话方法

6.3.1 不同领域的sql的区别

  位图索引与普通索引比较,à水平扩展性

  存储过程可以写的复杂点,直接穿参数进行存储,存储过程通常是被编译好的,他是一段代码在服务器端运行,通常我么只需要传入参数让他执行即可。这样子块的原因是除了编译还节约了网络开销。

         具体还是应该看实际的数据库场景,现在的实际的网络状况吗,目前许多数据库也会对sql进行预编译和cache操作,大事现在网络不是什么问题

         网络只要体现在延迟-一次传输一批数据,少访问io

         存储过程,就是操作存储的过程,就是对存储计算的过程描述,好多sql。。。

分析函数/窗口函数

6.3.2执行计划 ORACLE

 

不能使用动态绑定

ORcale

Pl/sql developer

 

 

Mysql explain<sql>

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值