当前位置: 首页 > 科技观察

MySQL排序原则和优化?本文将为大家一步步分析

时间:2023-03-14 20:27:16 科技观察

的简单介绍。对于面向业务(MySQL)的DBA或业务开发人员来说,按排序排序是一种常见的业务功能。将结果按照指定的字段进行排序,以满足前端展示的要求。需要。然而,排序操作也是慢查询排行榜的常客。这篇文章会从原理和实际案例优化,orderbyusagelimits等几个方面逐步了解orderbysorting。两个原理在理解orderbysorting原理之前,我强烈amway了两篇关于排序算法的文章《归并排序的实现》《经典排序算法》.MySQL支持正则排序和优化两种排序算法,而在MySQL5.6中,对orderbylimitM、N进行了特殊优化,这里列为第三种。2.1常规排序a从表t1中获取满足WHERE条件的记录b对于每条记录,取出该记录的主键+排序键(id,col2)放入排序缓冲区c如果排序缓冲区可以存储所有的(id,col2)满足条件的)是,则排序;否则,当排序缓冲区已满时,排序并固化到一个临时文件中。(排序算法使用快速排序算法)d如果排序时产生了临时文件,需要使用归并排序算法保证临时文件中的记录是有序的扫描排序好的(id,col2)对,并使用id检索SELECT需要返回的列(col1,col2,col3),将得到的结果集返回给用户。从上面的过程来看,是否使用文件排序主要看sortbuffer能否容纳需要排序的(id,col2)对。此缓冲区的大小由sort_buffer_size参数控制。另外,一次排序需要两次IO,一次是检索(id,col2),二是检索(col1,col2,col3)。由于返回的结果集是按col2排序的,所以id是乱序的。获取id(col1,col2,col3)时会产生大量随机IO。MySQL本身的二次优化,先将ids排序,放入buffer中,再进行钓鱼。这个buffer的大小是通过参数read_rnd_buffer_size来控制的,然后将record排序到fish中,以便将随机IO转化为顺序IO。2.2优化排序除了排序本身,传统的排序方法还需要额外的两个IO。与常规排序相比,优化后的排序方式减少了二次IO。主要区别在于它不是将(id,col2)放入排序缓冲区,而是放入(col1,col2,col3)。由于排序缓冲区中包含了查询所需的所有字段,因此排序完成后可以直接返回,无需检索数据。这种方法的代价是相同大小的排序缓冲区中可以存储的(col1,col2,col3)个数小于(id,col2)。如果排序缓冲区不够大,可能需要写入临时文件,导致额外的IO。当然,MySQL提供了参数max_length_for_sort_data,只有当排序后的元组小于max_length_for_sort_data时,才可以使用优化排序方式,否则只能使用常规排序方式。2.3优先队列排序为了得到最终的排序结果,不管怎样,我们都需要将所有满足条件的记录排序后再返回。那么相比于优化排序方式,是否还有优化空间呢?5.6版本在空间层面对OrderbylimitM,N语句进行了优化,增加了一种新的排序方式:优先队列,使用堆排序完成。堆排序算法的特点恰好可以解决限制M和N等排序问题,虽然仍然要求所有元素都参与排序,但只需要M+N个元组的排序缓冲空间。对于M和N较小的场景,基本上不会出现排序缓冲区不足而需要临时文件进行归并排序的问题。对于升序,使用大顶堆,最后堆中的元素构成最小的N个元素。对于降序,使用小顶堆,最后堆中的元素组成最大的N个元素。三优化通过以上原理的分析,我们知道排序的本质是通过一定的算法(消耗cpu操作、内存、临时文件IO)将结果集变成有序的结果集。如何优化呢?答案是在两个方面利用索引的有序性(MySQL的B+树索引默认是从小到大递增排序)来减少排序。最好的办法就是不直接排序。createtablet1(idintnotnullprimarykey,key_part1int(10)notnull,key_part2varchar(10)notnulldefault'',key_part3keyidx_kp1_kp2(key_part1,key_part2,key_part4),keyidx_kp3(id))engine=innodbdefaultcharset=utf8可以使用索引idx_kp1_kp2FROMt1ORDERBYkey,...;SELECT*FROMt1WHEREkey_part1=constantORDERBYkey_part2;SELECT*FROMt1ORDERBYkey_part1DESC,key_part2DESC;SELECT*FROMt1WHEREkey_part1=1ORDERBYkey_part1DESC,key_part2DESC;SELECT*FROMt1WHEREkey_part1>constantORDERBYkey_part1ASC;SELECT*FROMt1WHEREkey_part1constant2ORDERBYkey_part2温馨提示,Readersshouldlook看官方例子辩证,自己多练习。无法使用索引排序的情况,其实我觉得这是本文的重点。对于广大开发同学来说,不能用索引排序会更容易记住。1.在最常见的情况下,用于查找结果的索引(key2)与用于排序的索引(key1)不同,其中a=x和b=yorderbyid;SELECT*FROMt1WHEREkey2=constantORDERBYkey1;2、排序字段在不同的索引中,不能使用索引排序SELECT*FROMt1ORDERBYkey1,key2;3。排序字段的顺序与索引中列的顺序不一致,无法使用索引排序。例如,索引是键idx_kp1_kp2(key_part1,key_part2)SELECT*FROMt1ORDERBYkey_part2,key_part1;4。orderby索引中的升序和降序与索引中默认的升序和降序不一致,不能使用索引排序SELECT*FROMt1ORDERBYkey_part1DESC,key_part2ASC;5.ey_part1为范围查询,key_part2无法按index排序SELECT*FROMt1WHEREkey_part1>constantORDERBYkey_part2;5rderby和groupby字段列不一致SELECT*FROMt1WHEREkey_part1=constantORDERBYkey_part2groupbykey_part4;6、索引本身是乱序存储的,比如hash索引,不能利用索引的顺序。7.orderby字段只通过前缀,keyidx_col(col(10))select*fromt1orderbycol进行索引;8.对于带join的关联查询,并不是所有的排序字段都来自第一个表,使用explain查看执行计划第一个表类型值不是const。当无法避免排序操作时,如何优化呢?显然,首选使用索引的排序方式。在索引排序不理想的情况下,让MySQL尽可能选择使用第二种单向算法进行排序。.这样可以减少大量的随机IO操作,大大提高排序的效率。1.增加max_length_for_sort_data参数的设置在MySQL中,决定使用老式排序算法还是改进排序算法是由参数max_length_for_sort_data决定的。当所有返回字段的最大长度小于该参数值时,MySQL将选择改进的排序算法,否则,将选择老式算法。因此,如果MySQL有足够的内存来存储需要返回的非排序字段,可以增大该参数的值,让MySQL选择使用改进后的排序算法。2.去除不必要的返回字段当内存不是很充足时,不能简单地通过强行增大上述参数来强制MySQL使用改进的排序算法,否则可能会导致MySQL不得不将数据分成很多段,然后进行排序它出来,它可能不会得到回报。这时候需要去掉不需要的返回字段,让返回结果的长度适应max_length_for_sort_data参数的限制。同时,还要规范MySQL开发规范,尽量避免大字段。Whenaselectquerycolumncontainsalargefieldblobortext,MySQLwillchoosearegularsort.“要使用的算法。它通常使用修改后的算法,除非涉及或列,在这种情况下,它使用原始算法。”3.增加sort_buffer_size参数设置,如果这个值太小,就把你返回一次的item加进去,如果数量太多,很可能要排序很多次,然后*??*会把每次的排序结果拼接起来,这会更慢。增加sort_buffer_size并不是让MySQL选择一个改进的排序算法。就是让MySQL在排序的过程中尽量减少需要排序的数据的切分,因为切分会导致MySQL使用临时表进行exchange排序。但是这个值并不是越大越好:1.sort_buffer_size是一个连接级别的参数,当每个连接第一次需要使用这个缓冲区时,一次性分配设置的内存。2、sort_buffer_size越大越好。由于是连接级别的参数,过大的设置+高并发可能会耗尽系统内存资源。3.据说当sort_buffer_size超过2M时,会使用mmap()代替malloc()进行内存分配,导致效率降低。四篇参考文章[1]MySQL官方文档调优排序[2]MySQL排序原理及案例分析[3]淘宝MySQL月报