MySQL数据库性能优化_第1页
MySQL数据库性能优化_第2页
MySQL数据库性能优化_第3页
MySQL数据库性能优化_第4页
MySQL数据库性能优化_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

MySQL数据库性能优化作者:Sky.Jian|可以任意转载,但转载时务必以超链接形式标明文章原始出处和作者信息及版权声明链接:/database/mysql-perfornamce-tuning-cache-parameter在平时被问及最多的问题就是关于MySQL数据库性能优化方面的问题,所以最近打算写一个MySQL数据库性能优化方面的系列文章,希望对初中级MySQLDBA以及其他对MySQL性能优化感兴趣的朋友们有所帮助。第1章MySQL数据库性能优化之缓存参数优化/database/mysql-perfornamce-tuning-cache-parameter数据库属于IO密集型的应用程序,其主要职责就是数据的管理及存储工作。而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个IO是在毫秒级别,二者相差3个数量级。所以,要优化数据库,首先第一步需要优化的就是IO,尽可能将磁盘IO转化为内存IO。本文先从MySQL数据库io相关参数(缓存参数)的角度来看看可以通过哪些参数进IO优化:query_cache_size/query_cache_type(global)Querycache作用于整个MySQLInstance,主要用来缓存MySQL中的ResultSet,也就是一条SQL语句执行的结果集,所以仅仅只能针对select语句。当我们打开了QueryCache功能,MySQL在接受到一条select语句的请求后,如果该语句满足QueryCache的要求(未显式说明不允许使用QueryCache,或者已经显式申明需要使用QueryCache),MySQL会直接根据预先设定好的HASH算法将接受到的select语句以字符串方式进行hash,然后到QueryCache中直接查找是否已经缓存。也就是说,如果已经在缓存中,该select请求就会直接将数据返回,从而省略了后面所有的步骤(如SQL语句的解析,优化器优化以及向存储引擎请求数据等),极大的提高性能。当然,QueryCache也有一个致命的缺陷,那就是当某个表的数据有任何任何变化,都会导致所有引用了该表的select语句在QueryCache中的缓存数据失效。所以,当我们的数据变化非常频繁的情况下,使用QueryCache可能会得不偿失。QueryCache的使用需要多个参数配合,其中最为关键的是query_cache_size和query_cache_type,前者设置用于缓存ResultSet的内存大小,后者设置在何场景下使用QueryCache。在以往的经验来看,如果不是用来缓存基本不变的数据的MySQL数据库,query_cache_size一般256MB是一个比较合适的大小。当然,这可以通过计算QueryCache的命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))来进行调整。query_cache_type可以设置为0(OFF),1(ON)或者2(DEMOND),分别表示完全不使用querycache,除显式要求不使用querycache(使用sql_no_cache)之外的所有的select都使用querycache,只有显示要求才使用querycache(使用sql_cache)。binlog_cache_size(global)BinlogCache用于在打开了二进制日志(binlog)记录功能的环境,是MySQL用来提高binlog的记录效率而设计的一个用于短时间内临时缓存binlog数据的内存区域。一般来说,如果我们的数据库中没有什么大事务,写入也不是特别频繁,2MB〜4MB是一个合适的选择。但是如果我们的数据库大事务较多,写入量比较大,可与适当调高binlog_cache_size。同时,我们可以通过binlog_cache_use以及binlog_cache_disk_use来分析设置的binlog_cache_size是否足够,是否有大量的binlog_cache由于内存大小不够而使用临时文件(binlog_cache_disk_use)来缓存了。key_buffer_size(global)KeyBuffer可能是大家最为熟悉的一个MySQL缓存参数了,尤其是在MySQL没有更换默认存储引擎的时候,很多朋友可能会发现,默认的MySQL配置文件中设置最大的一个内存参数就是这个参数了。key_buffer_size参数用来设置用于缓存MylSAM存储引擎中索引文件的内存区域大小。如果我们有足够的内存,这个缓存区域最好是能够存放下我们所有的MylSAM引擎表的所有索引,以尽可能提高性能。此外,当我们在使用MylSAM存储的时候有一个及其重要的点需要注意,由于MylSAM引擎的特性限制了他仅仅只会缓存索引块到内存中,而不会缓存表数据库块。所以,我们的SQL一定要尽可能让过滤条件都在索引中,以便让缓存帮助我们提高查询效率。bulk_insert_buffer_size(thread)和key_buffer_size一样,这个参数同样也仅作用于使用MylSAM存储引擎,用来缓存批量插入数据的时候临时缓存写入数据。当我们使用如下几种数据写入语句的时候,会使用这个内存区域来缓存批量结构的数据以帮助批量写入数据文件:insert…select…insert…values(…),(•••),(…)…loaddatainfile…into…(非空表)innodb_buffer_pool_size(global)当我们使用InnoDB存储引擎的时候,innodb_buffer_pool_size参数可能是影响我们性能的最为关键的一个参数了,他用来设置用于缓存InnoDB索引及数据块的内存区域大小,类似于MylSAM存储引擎的key_buffer_size参数,当然,可能更像是Oracle的db_cache_size。简单来说,当我们操作一个InnoDB表的时候,返回的所有数据或者去数据过程中用到的任何一个索引块,都会在这个内存区域中走一遭。和key_buffer_size对于MylSAM引擎一样,innodb_buffer_pool_size设置了InnoDB存储引擎需求最大的一块内存区域的大小,直接关系到InnoDB存储引擎的性能,所以如果我们有足够的内存,尽可将该参数设置到足够打,将尽可能多的InnoDB的索引及数据都放入到该缓存区域中,直至全部。我们可以通过(Innodb_buffer_pool_read_requests-Innodb_buffer_pool_reads)/Innodb_buffer_pool_read_requests*100%计算缓存命中率,并根据命中率来调整innodb_buffer_pool_size参数大小进行优化。innodb_additional_mem_pool_size(global)这个参数我们平时调整的可能不是太多,很多人都使用了默认值,可能很多人都不是太熟悉这个参数的作用。innodb_additional_mem_pool_size设置了InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间大小,所以当我们一个MySQLInstance中的数据库对象非常多的时候,是需要适当调整该参数的大小以确保所有数据都能存放在内存中提高访问效率的。这个参数大小是否足够还是比较容易知道的,因为当过小的时候,MySQL会记录Warning信息到数据库的errorlog中,这时候你就知道该调整这个参数大小了。innodb_log_buffer_size(global)这是InnoDB存储引擎的事务日志所使用的缓冲区。类似于BinlogBuffer,InnoDB在写事务日志的时候,为了提高性能,也是先将信息写入InnofbLogBuffer中,当满足innodb_flush_log_trx_commit参数所设置的相应条件(或者日志缓冲区写满)之后,才会将日志写到文件(或者同步到磁盘)中。可以通过innodb_log_buffer_size参数设置其可以使用的最大内存空间。注:innodb_flush_log_trx_commit参数对InnoDBLog的写入性能有非常关键的影响。该参数可以设置为0,1,2,解释如下:0:logbuffer中的数据将以每秒一次的频率写入到logfile中,且同时会进行文件系统到磁盘的同步操作,但是每个事务的commit并不会触发任何logbuffer到logfile的刷新或者文件系统到磁盘的刷新操作;1:在每次事务提交的时候将logbuffer中的数据都会写入到logfile,同时也会触发文件系统到磁盘的同步;2:事务提交会触发logbuffer到logfile的刷新,但并不会触发磁盘文件系统到磁盘的同步。此外,每秒会有一次文件系统到磁盘同步操作。此外,MySQL文档中还提到,这几种设置中的每秒同步一次的机制,可能并不会完全确保非常准确的每秒就一定会发生同步,还取决于进程调度的问题。实际上,InnoDB能否真正满足此参数所设置值代表的意义正常Recovery还是受到了不同OS下文件系统以及磁盘本身的限制,可能有些时候在并没有真正完成磁盘同步的情况下也会告诉mysqld已经完成了磁盘同步。innodb_max_dirty_pages_pct(global)这个参数和上面的各个参数不同,他不是用来设置用于缓存某种数据的内存大小的一个参数,而是用来控制在InnoDBBufferPool中可以不用写入数据文件中的DirtyPage的比例(已经被修但还没有从内存中写入到数据文件的脏数据)。这个比例值越大,从内存到磁盘的写入操作就会相对减少,所以能够一定程度下减少写入操作的磁盘IO。但是,如果这个比例值过大,当数据库Crash之后重启的时间可能就会很长,因为会有大量的事务数据需要从日志文件恢复出来写入数据文件中。同时,过大的比例值同时可能也会造成在达到比例设定上限后的flush操作“过猛”而导致性能波动很大。上面这几个参数是MySQL中为了减少磁盘物理IO而设计的主要参数,对MySQL的性能起到了至关重要的作用。—EOF—按照mcsrainbow朋友的要求,这里列一下根据以往经验得到的相关参数的建议值:•binlog_cache_size:一般环境2MB〜4MB是一个合适的选择,事务较大且写入频繁的数据库环境可以适当调大,但不建议超过32MBkey_buffer_size:如果不使用MylSAM存储引擎,16MB足以,用来缓存一些系统表信息等。如果使用MylSAM存储引擎,在内存允许的情况下,尽可能将所有索引放入内存,简单来说就是“越大越好”bulk_insert_buffer_size:如果经常性的需要使用批量插入的特殊语句(上面有说明)来插入数据,可以适当调大该参数至16MB〜32MB,不建议继续增大,某人8MBinnodb_buffer_pool_size:如果不使用InnoDB存储引擎,可以不用调整这个参数,如果需要使用,在内存允许的情况下,尽可能将所有的InnoDB数据文件存放如内存中,同样将但来说也是“越大越好”innodb_additional_mem_pool_size:一般的数据库建议调整到8MB〜16MB,如果表特别多,可以调整到32MB,可以根据errorlog中的信息判断是否需要增大innodb_log_buffer_size:默认是1MB,系的如频繁的系统可适当增大至4MB〜8MB。当然如上面介绍所说,这个参数实际上还和另外的flush参数相关。一般来说不建议超过32MBinnodb_max_dirty_pages_pct:根据以往的经验,重启恢复的数据如果要超过1GB的话,启动速度会比较慢,几乎难以接受,所以建议不大于1GB/innodb_buffer_pool_size(GB)*100这个值。当然,如果你能够忍受启动时间比较长,而且希望尽量减少内存至磁盘的flush,可以将这个值调整到90,但不建议超过90注:以上取值范围仅仅只是我的根据以往遇到的数据库场景所得到的一些优化经验值,并不一定适用于所有场景所以在实际优化过程中还需要大家自己不断的调整分析,也欢迎大家随时通过Mail与我联系沟通交流优化或者是架构方面的技术,一起探讨相互学习。第2章MySQL数据库性能优化之表结构•数据类型选择数据库操作中最为耗时的操作就是IO处理,大部分数据库操作90%以上的时间都花在了IO读写上面。所以尽可能减少IO读写量,可以在很大程度上提高数据库操作的性能。我们无法改变数据库中需要存储的数据,但是我们可以在这些数据的存储方式方面花一些心思。下面的这些关于字段类型的优化建议主要适用于记录条数较多,数据量较大的场景,因为精细化的数据类型设置可能带来维护成本的提高,过度优化也可能会带来其他的问题:数字类型:非万不得已不要使用DOUBLE,不仅仅只是存储长度的问题,同时还会存在精确性的问题。同样,固定精度的小数,也不建议使用DECIMAL,建议乘以固定倍数转换成整数存储,可以大大节省存储空间,且不会带来任何附加维护成本。对于整数的存储,在数据量较大的情况下,建议区分开TINYINT/INT/BIGINT的选择,因为三者所占用的存储空间也有很大的差别,能确定不会使用负数的字段,建议添加unsigned定义。当然,如果数据量较小的数据库,也可以不用严格区分三个整数类型。字符类型:非万不得已不要使用TEXT数据类型,其处理方式决定了他的性能要低于char或者是varchar类型的处理。定长字段,建议使用CHAR类型,不定长字段尽量使用VARCHAR,且仅仅设定适当的最大长度,而不是非常随意的给一个很大的最大长度限定,因为不同的长度范围,MySQL也会有不一样的存储处理。时间类型:尽量使用TIMESTAMP类型,因为其存储空间只需要DATETIME类型的一半。对于只需要精确到某一天的数据类型,建议使用DATE类型,因为他的存储空间只需要3个字节,比TIMESTAMP还少。不建议通过INT类型类存储一个unixtimestamp的值,因为这太不直观,会给维护带来不必要的麻烦,同时还不会带来任何好处。ENUM&SET:对于状态字段,可以尝试使用ENUM来存放,因为可以极大的降低存储空间,而且即使需要增加新的类型,只要增加于末尾,修改结构也不需要重建表数据。如果是存放可预先定义的属性数据呢?可以尝试使用SET类型,即使存在多种属性,同样可以游刃有余,同时还可以节省不小的存储空间。LOB类型:强烈反对在数据库中存放LOB类型数据,虽然数据库提供了这样的功能,但这不是他所擅长的,我们更应该让合适的工具做他擅长的事情,才能将其发挥到极致。在数据库中存储LOB数据就像让一个多年前在学校学过一点Java的营销专业人员来写Java代码一样。•字符编码字符集直接决定了数据在MySQL中的存储编码方式,由于同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。纯拉丁字符能表示的内容,没必要选择latinl之外的其他字符编码,因为这会节省大量的存储空间如果我们可以确定不需要存放多种语言,就没必要非得使用UTF8或者其他UNICODE字符类型,这回造成大量的存储空间浪费MySQL的数据类型可以精确到字段,所以当我们需要大型数据库中存放多字节数据的时候,可以通过对不同表不同字段使用不同的数据类型来较大程度减小数据存储量,进而降低IO操作次数并提高缓存命中率•适当拆分有些时候,我们可能会希望将一个完整的对象对应于一张数据库表,这对于应用程序开发来说是很有好的,但是有些时候可能会在性能上带来较大的问题。当我们的表中存在类似于TEXT或者是很大的VARCHAR类型的大字段的时候,如果我们大部分访问这张表的时候都不需要这个字段,我们就该义无反顾的将其拆分到另外的独立表中,以减少常用数据所占用的存储空间。这样做的一个明显好处就是每个数据块中可以存储的数据条数可以大大增加,既减少物理IO次数,也能大大提高内存中的缓存命中率。上面几点的优化都是为了减少每条记录的存储空间大小,让每个数据库中能够存储更多的记录条数,以达到减少IO操作次数,提高缓存命中率。下面这个优化建议可能很多开发人员都会觉得不太理解,因为这是典型的反范式设计,而且也和上面的几点优化建议的目标相违背。•适度冗余为什么我们要冗余?这不是增加了每条数据的大小,减少了每个数据块可存放记录条数吗?确实,这样做是会增大每条记录的大小,降低每条记录中可存放数据的条数,但是在有些场景下我们仍然还是不得不这样做:被频繁引用且只能通过Join2张(或者更多)大表的方式才能得到的独立小字段这样的场景由于每次Join仅仅只是为了取得某个小字段的值,Join到的记录又大,会造成大量不必要的IO,完全可以通过空间换取时间的方式来优化。不过,冗余的同时需要确保数据的一致性不会遭到破坏,确保更新的同时冗余字段也被更新•尽量使用NOTNULLNULL类型比较特殊,SQL难优化。虽然MySQLNULL类型和Oracle的NULL有差异,会进入索引中,但如果是一个组合索引,那么这个NULL类型的字段会极大影响整个索引的效率。此外,NULL在索引中的处理也是特殊的,也会占用额外的存放空间。很多人觉得NULL会节省一些空间,所以尽量让NULL来达到节省IO的目的,但是大部分时候这会适得其反,虽然空间上可能确实有一定节省,倒是带来了很多其他的优化问题,不但没有将IO量省下来,反而加大了SQL的IO量。所以尽量确保DEFAULT值不是NULL,也是一个很好的表结构设计优化习惯。第3章MySQL数据库性能优化之SQL优化有人反馈之前几篇文章过于理论缺少实际操作细节,这篇文章就多一些可操作性的内容吧。注:这篇文章是以MySQL为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础•优化目标减少IO次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是IO操作所占用的,减少IO次数是SQL优化中需要第一优先考虑,当然,也是收效最明显的优化手段。降低CPU计算除了IO瓶颈之外,SQL优化中需要考虑的就是CPU运算量的优化了。orderby,groupby,distinct…都是消耗CPU的大户(这些操作基本上都是CPU处理内存中的数据比较运算)。当我们的IO优化做到一定阶段之后,降低CPU计算也就成为了我们SQL优化的重要目标•优化方法改变SQL执行计划明确了优化目标之后,我们需要确定达到我们目标的方法。对于SQL语句来说,达到上述2个目标的方法其实只有一个,那就是改变SQL的执行计划,让他尽量“少走弯路”,尽量通过各种“捷径”来找到我们需要的数据,以达到“减少IO次数”和“降低CPU计算”的目标•常见误区count(1)和count(primary_key)优于count(*)很多人为了统计记录条数,就使用count(1)和count(primary_key)而不是count(*),他们认为这样性能更好,其实这是一个误区。对于有些场景,这样做可能性能会更差,应为数据库对count(*)计数操作做了一些特别的优化。count(column)和count(*)是-一样的这个误区甚至在很多的资深工程师或者是DBA中都普遍存在,很多人都会认为这是理所当然的。实际上,count(column)和count(*)是一个完全不一样的操作,所代表的意义也完全不一样。count(column)是表示结果集中有多少个column字段不为空的记录count(*)是表示整个结果集有多少条记录selecta,bfrom…比selecta,b,cfrom…可以让数据库访问更少的数据量这个误区主要存在于大量的开发人员中,主要原因是对数据库的存储原理不是太了解。实际上,大多数关系型数据库都是按照行(row)的方式存储,而数据存取操作都是以一个固定大小的IO单元(被称作block或者page)为单位,一般为4KB,8KB…大多数时候,每个IO单元中存储了多行,每行都是存储了该行的所有字段(lob等特殊类型字段除外)。所以,我们是取一个字段还是多个字段,实际上数据库在表中需要访问的数据量其实是一样的。当然,也有例外情况,那就是我们的这个查询在索引中就可以完成,也就是说当只取a,b两个字段的时候,不需要回表,而c这个字段不在使用的索引中,需要回表取得其数据。在这样的情况下,二者的IO量会有较大差异。orderby一定需要排序操作我们知道索引数据实际上是有序的,如果我们的需要的数据和某个索引的顺序一致,而且我们的查询又通过这个索引来执行,那么数据库一般会省略排序操作,而直接将数据返回,因为数据库知道数据已经满足我们的排序需求了。实际上,利用索引来优化有排序需求的SQL,是一个非常重要的优化手段延伸阅读:MySQLORDERBY的实现分析,MySQL中GROUPBY基本实现原理以及MySQLDISTINCT的基本实现原理这3篇文章中有更为深入的分析,尤其是第一篇执行计划中有filesort就会进行磁盘文件排序有这个误区其实并不能怪我们,而是因为MySQL开发者在用词方面的问题。filesort是我们在使用explain命令查看一条SQL的执行计划的时候可能会看到在“Extra”一列显示的信息。实际上,只要一条SQL语句需要进行排序操作,都会显示“Usingfilesort”,这并不表示就会有文件排序操作。延伸阅读:理解MySQLExplain命令输出中的filesort,我在这里有更为详细的介绍基本原则尽量少joinMySQL的优势在于简单,但这在某些方面其实也是其劣势°MySQL优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表Join,一方面由于其优化器受限,再者在Join这方面所下的功夫还不够,所以性能表现离Oracle等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。尽量少排序排序操作会消耗较多的CPU资源,所以减少排序可以在缓存命中率高等IO能力足够的场景下会较大影响SQL的响应时间。对于MySQL来说,减少排序有多种办法,比如:・上面误区中提到的通过利用索引来排序的方式进行优化・减少参与排序的记录条数・非必要不对数据进行排序_.••・尽量避免select*很多人看到这一点后觉得比较难理解,上面不是在误区中刚刚说select子句中字段的多少并不会影响到读取的数据吗?是的,大多数时候并不会影响到IO量,但是当我们还存在orderby操作的时候,select子句中的字段多少会在很大程度上影响到我们的排序效率,这一点可以通过我之前一篇介绍MySQLORDERBY的实现分析的文章中有较为详细的介绍。此外,上面误区中不是也说了,只是大多数时候是不会影响到IO量,当我们的查询结果仅仅只需要在索引中就能找到的时候,还是会极大减少IO量的。尽量用join代替子查询虽然Join性能并不佳,但是和MySQL的子查询比起来还是有非常大的性能优势°MySQL的子查询执行计划一直存在较大的问题,虽然这个问题已经存在多年,但是到目前已经发布的所有稳定版本中都普遍存在,一直没有太大改善。虽然官方也在很早就承认这一问题,并且承诺尽快解决,但是至少到目前为止我们还没有看到哪一个版本较好的解决了这一问题。尽量少or当where子句中存在多个条件以“或”并存的时候,MySQL的优化器并没有很好的解决其执行计划优化问题,再加上MySQL特有的SQL与Storage分层架构方式,造成了其性能比较低下,很多时候使用unionall或者是union(必要的时候)的方式来代替“or”会得到更好的效果。尽量用unionall代替unionunion和unionall的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的CPU运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用unionall而不是union。尽量早过滤这一优化策略其实最常见于索引的优化设计中(将过滤性更好的字段放得更靠前)。在SQL编写中同样可以使用这一原则来优化一些Join的SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表Join,这样可以尽可能多的减少不必要的IO操作,大大节省IO操作所消耗的时间。避免类型转换这里所说的“类型转换”是指where子句中出现column字段的类型和传入的参数类型不一致的时候发生的类型转换:-人为在column_name上通过转换函数进行转换直接导致MySQL(实际上其他数据库也会有同样的问题)无法使用索引,如果非要转换,应该在传入的参数上进行转换・由数据库自己进行转换如果我们传入的数据类型和字段类型不一致,同时我们又没有做任何类型转换处理,MySQL可能会自己对我们的数据进行类型转换操作,也可能不进行处理而交由存储引擎去处理,这样一来,就会出现索引无法使用的情况而造成执行计划问题。优先优化高并发的SQL,而不是执行频率低某些“大”SQL对于破坏性来说,高并发的SQL总是会比低频率的来得大,因为高并发的SQL一旦出现问题,甚至不会给我们任何喘息的机会就会将系统压跨。而对于一些虽然需要消耗大量IO而且响应很慢的SQL,由于频率低,即使遇到,最多就是让整个系统响应慢一点,但至少可能撑一会儿,让我们有缓冲的机会。从全局出发优化,而不是片面调整SQL优化不能是单独针对某一个进行,而应充分考虑系统中所有的SQL,尤其是在通过调整索引优化SQL的执行计划的时候,千万不能顾此失彼,因小失大。尽可能对每一条运行在数据库中的SQL进行explain优化SQL,需要做到心中有数,知道SQL的执行计划才能判断是否有优化余地,才能判断是否存在执行计划问题。在对数据库中运行的SQL进行了一段时间的优化之后,很明显的问题SQL可能已经很少了,大多都需要去发掘,这时候就需要进行大量的explain操作收集执行计划,并判断是否需要进行优化。第四章MySQL数据库性能优化之索引优化大家都知道索引对于数据访问的性能有非常关键的作用,都知道索引可以提高数据访问效率。为什么索引能提高数据访问性能?他会不会有“副作用”?是不是索引创建越多,性能就越好?到底该如何设计索引,才能最大限度的发挥其效能?这篇文章主要是带着上面这几个问题来做一个简要的分析,同时排除了业务场景所带来的特殊性,请不要纠结业务场景的影响。索引为什么能提高数据访问性能?很多人只知道索引能够提高数据库的性能,但并不是特别了解其原理,其实我们可以用一个生活中的示例来理解。我们让一位不太懂计算机的朋友去图书馆确认一本叫做《MySQL性能调优与架构设计》的书是否在藏,这样对他说:“请帮我借一本计算机类的数据库书籍,是属于MySQL数据库范畴的,叫做《MySQL性能调优与架构设计》”。朋友会根据所属类别,前往存放“计算机”书籍区域的书架,然后再寻找“数据库”类存放位置,再找到一堆讲述“MySQL”的书籍,最后可能发现目标在藏(也可能已经借出不在书架上)。在这个过程中:“计算机”->“数据库”-〉"MySQL”->“在藏”->《MySQL性能调优与架构设计》其实就是一个“根据索引查找数据”的典型案例,“计算机”->“数据库”-〉"MySQL”->“在藏”就是朋友查找书籍的索引。假设没有这个索引,那查找这本书的过程会变成怎样呢?朋友只能从图书馆入口一个书架一个书架的“遍历”,直到找到《MySQL性能调优与架构设计》这本书为止。如果幸运,可能在第一个书架就找到。但如果不幸呢,那就惨了,可能要将整个图书馆所有的书架都找一遍才能找到我们想要的这本书。注:这个例子中的“索引”是记录在朋友大脑中的,实际上,每个图书馆都会有一个非常全的实际存在的索引系统(大多位于入口显眼处),由很多个贴上了明显标签的小抽屉构成。这个索引系统中存放这非常齐全详尽的索引数据,标识出我们需要查找的“目标”在某个区域的某个书架上。而且每当有新的书籍入库,旧的书籍销毁以及书记信息修改,都需要对索引系统进行及时的修正。下面我们通过上面这个生活中的小示例,来分析一下索引,看看能的出哪些结论?•索引有哪些“副作用”?图书的变更(增,删,改)都需要修订索引,索引存在额外的维护成本查找翻阅索引系统需要消耗时间,索引存在额外的访问成本这个索引系统需要一个地方来存放,索引存在额外的空间成本•索引是不是越多越好?如果我们的这个图书馆只是一个进出中转站,里面的新书进来后很快就会转发去其他图书馆而从这个馆藏中“清除”,那我们的索引就只会不断的修改,而很少会被用来查找图书所以,对于类似于这样的存在非常大更新量的数据索引的维护成本会非常高,如果其检索需求很少,而且对检索效率并没有非常高的要求的时候,我们并不建议创建索引,或者是尽量减少索引。如果我们的书籍量少到只有几本或者就只有一个书架,索引并不会带来什么作用,甚至可能还会浪费一些查找索引所花费的时间。所以,对于数据量极小到通过索引检索还不如直接遍历来得快的数据,也并不适合使用索引。如果我们的图书馆只有一个10平方的面积,现在连放书架都已经非常拥挤,而且馆藏还在不断增加,我们还能考虑创建索引吗?所以,当我们连存储基础数据的空间都捉襟见肘的时候我们也应该尽量减少低效或者是去除索引。索引该如何设计才高效?如果我们仅仅只是这样告诉对方的:“帮我确认一本数据库类别的讲述MySQL的叫做《MySQL性能调优与架构设计》的书是否在藏”,结果又会如何呢?朋友只能一个大类区域一个大类区域的去寻找“数据库”类别,然后再找到“MySQL”范畴,再看到我们所需是否在藏。由于我们少说了一个“计算机类”,朋友就必须到每一个大类去寻找。所以,我们应该尽量让查找条件尽可能多的在索引中尽可能通过索引完成所有过滤,回表只是取出额外的数据字段。如果我们是这样说的:“帮我确认一本讲述MySQL的数据库范畴的计算机丛书,叫做《MySQL性能调优与架构设计》,看是否在藏”。如果这位朋友并不知道计算机是一个大类,也不知道数据库属于计算机大类,那这位朋友就悲剧了。首先他得遍历每个类别确认“MySQL”存在于哪些类别中,然后从包含“MySQL”

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论