百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

mysql数据库调优(二) mysql数据库性能优化

wptr33 2024-11-09 15:00 57 浏览

第五、查询优化

1、查询慢的原因:网络因素、CPU、IO、上下文切换、系统调用、生成统计信息、锁等待时间等

2、优化数据库访问:查询性能地下的原因是访问的数据太多,某些查询不可避免的需要筛选大量的数据,可以通过减少访问数据量的方式优化;1、确认应用程序是否在检索大量超过需要的数据;2、确认mysql服务器层是否在分析大量超过需要的数据行

3、执行过程优化:

1、查询缓存:在解析一个查询语句之前,如果查询缓存是打开的,那么mysql会优先检查这个查询是否命中查询缓存中的数据,如果查询恰好命中了查询缓存,那么会在返回结果之前会检查用户权限,如果权限没有问题,那么mysql会跳过所有的阶段,就直接从缓存中拿到结果并返回给客户端;

2、查询优化处理:mysql查询完缓存之后会经过以下几个步骤:解析SQL、预处理、优化SQL执行计划,这几个步骤出现任何的错误,都可能会终止查询;

1、语法解析器和预处理:mysql通过关键字将SQL语句进行解析,并生成一颗解析树,mysql解析器将使用mysql语法规则验证和解析查询,例如验证使用使用了错误的关键字或者顺序是否正确等等,预处理器会进一步检查解析树是否合法,例如表名和列名是否存在,是否有歧义,还会验证权限等等

2、查询优化器:

1、select count(*) from table;show status like 'last_query_cost'; 可以看到这条查询语句大概需要做1104个数据页才能找到对应的数据,这是经过一系列的统计信息计算来的(每个表或者索引的页面个数;索引的基数;索引和数据行的长度;索引的分布情况)

2、很多时候mysql会选择错误的执行计划(统计信息不准确(InnoDB因为其mvcc的架构,并不能维护一个数据表的行数的精确统计信息

);执行计划的成本估算不等同于实际执行的成本(有时候某个执行计划虽然需要读取更多的页面,但是他的成本却更小,因为如果这些页面都是顺序读或者这些页面都已经在内存中的话,那么它的访问成本将很小,mysql层面并不知道哪些页面在内存中,哪些在磁盘,所以查询之际执行过程中到底需要多少次IO是无法得知的);mysql的最优可能跟你想的不一样(mysql的优化是基于成本模型的优化,但是有可能不是最快的优化);mysql不考虑其他并发执行的查询;mysql不会考虑不受其控制的操作成本(执行存储过程或者用户自定义函数的成本));

3、优化器的优化策略:1、静态优化,直接对解析树进行分析,并完成优化;2、动态优化,动态优化与查询的上下文有关,也可能跟取值、索引对应的行数有关;3、mysql对查询的静态优化只需要一次,但对动态优化在每次执行时都需要重新评估

4、优化器的优化类型:重新定义关联表的顺序(数据表的关联并不总是按照在查询中指定的顺序进行,决定关联顺序时优化器很重要的功能);将外连接转化为内连接,内连接的效率要高于外连接;使用等价变换规则,mysql可以使用一些等价变化来简化并规划表达式;优化count、min、max索引和列是否可以为空通常可以帮助mysql优化这类表达式:例如,要找到某一列的最小值,只需要查询索引的最左端的记录即可,不需要全文扫描比较;预估并转化为常数表达式,当mysql检测到一个表达式可以转化为常数的时候,就会一直把该表达式作为常数进行处理;索引覆盖扫描,当索引中的列包含所有查询中需要使用的列的时候,可以使用覆盖索引;子查询优化,mysql在某些情况下可以将子查询转换一种效率更高的形式,从而减少多个查询多次对数据进行访问,例如将经常查询的数据放入到缓存中;等值传播:如果两个列的值通过等式关联,那么mysql能够把其中一个列的where条件传递到另一个上:explain select film.film_id from film inner join film_actor using(film_id) where film.film_id > 500;这里使用film_id字段进行等值关联,film_id这个列不仅适用于film表而且适用于film_actor表explain select film.film_id from film inner join film_actor using(film_id) where film.film_id > 500 and film_actor.film_id > 500;

3、关联查询:join的实现原理,Simple Nested-Loop Join,r表示驱动表、s表示驱动表,从图中可以看出从r中拿到数据匹配s开销很大

Index Nested-Loop Join要求非驱动表上有索引,可以通过索引来减少比较,加速查询;在查询时,驱动表(r)会根据关联字段的索引进行查询,当在索引上找到符合的值,在进行回表查询

Block Nested-Loop Join如果有索引会选取第二种方式进行join如果没有索引才会使用Block Nested-Loop Join;

(1)Join Buffer会缓存所有参与查询的列而不是只有Join的列。

(2)可以通过调整join_buffer_size缓存大小

(3)join_buffer_size的默认值是256K,join_buffer_size的最大值在MySQL 5.1.22版本前是4G-1,而之后的版本才能在64位操作系统下申请大于4G的Join Buffer空间。

(4)使用Block Nested-Loop Join算法需要开启优化器管理配置的optimizer_switch的设置block_nested_loop为on,默认为开启。

show variables like '%optimizer_switch%'

4、排序优化:无论如何排序都是一个成本很高的操作,所以从性能的角度出发,应该尽可能避免排序或者尽可能避免对大量数据进行排序。

推荐使用利用索引进行排序,但是当不能使用索引的时候,mysql就需要自己进行排序,如果数据量小则再内存中进行,如果数据量大就需要使用磁盘,mysql中称之为filesort。如果需要排序的数据量小于排序缓冲区(show variables like '%sort_buffer_size%';),mysql使用内存进行快速排序操作,如果内存不够排序,那么mysql就会先将树分块,对每个独立的块使用快速排序进行排序,并将各个块的排序结果存放再磁盘上,然后将各个排好序的块进行合并,最后返回排序结果。

排序算法:两次传值排序,第一次数据读取是将需要排序的字段读取出来,然后进行排序,第二次是将排好序的结果按照需要去读取数据行。

这种方式效率比较低,原因是第二次读取数据的时候因为已经排好序,需要去读取所有记录而此时更多的是随机IO,读取数据成本会比较高

两次传输的优势,在排序的时候存储尽可能少的数据,让排序缓冲区可以尽可能多的容纳行数来进行排序操作。单次传输排序:先读取查询所需要的所有列,然后再根据给定列进行排序,最后直接返回排序结果,此方式只需要一次顺序IO读取所有的数据,而无须任何的随机IO,问题在于查询的列特别多的时候,会占用大量的存储空间,无法存储大量的数据。当需要排序的列的总大小超过max_length_for_sort_data定义的字节,mysql会选择双次排序,反之使用单次排序,当然,用户可以设置此参数的值来选择排序的方式。

4、优化特定类型的优化:

1、优化count查询:没有where条件时,count(*)才是最快的,在myisam的count中;使用近似值,在某些应用场景中,不需要完全精确的值,可以参考使用近似值来代替,比如可以使用explain来获取近似的值;其实在很多OLAP的应用中,需要计算某一个列值的基数,有一个计算近似值的算法叫hyperloglog。更复杂的优化:一般情况下,count()需要扫描大量的行才能获取精确的数据,其实很难优化,在实际操作的时候可以考虑使用索引覆盖扫描,或者增加汇总表,或者增加外部缓存系统。

2、优化关联查询:确保on或者using子句中的列上有索引,在创建索引的时候就要考虑到关联的顺序,当表A和表B使用列C关联的时候,如果优化器的关联顺序是B、A,那么就不需要再B表的对应列上建上索引,没有用到的索引只会带来额外的负担,一般情况下来说,只需要在关联顺序中的第二个表的相应列上创建索引。确保任何的groupby和order by中的表达式只涉及到一个表中的列,这样mysql才有可能使用索引来优化这个过程。

3、优化子查询:子查询的优化最重要的优化建议是尽可能使用关联查询代替

4、优化limit分页:在很多应用场景中我们需要将数据进行分页,一般会使用limit加上偏移量的方法实现,同时加上合适的orderby 的子句,如果这种方式有索引的帮助,效率通常不错,否则的化需要进行大量的文件排序操作,还有一种情况,当偏移量非常大的时候,前面的大部分数据都会被抛弃,这样的代价太高。要优化这种查询的话,要么是在页面中限制分页的数量,要么优化大偏移量的性能。(优化此类查询的最简单的办法就是尽可能地使用覆盖索引,而不是查询所有的列);

5、优化union查询:mysql总是通过创建并填充临时表的方式来执行union查询,因此很多优化策略在union查询中都没法很好的使用。经常需要手工的将where、limit、order by等子句下推到各个子查询中,以便优化器可以充分利用这些条件进行优化;除非确实需要服务器消除重复的行,否则一定要使用union all,因此没有all关键字,mysql会在查询的时候给临时表加上distinct的关键字,这个操作的代价很高。

第六、分区表

1、分区表应用场景:表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据;分区表的数据更容易维护(批量删除大量数据可以使用清除整个分区的方式;对一个独立分区进行优化、检查、修复等操作);分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备;可以使用分区表来避免某些特殊的瓶颈(innodb的单个索引的互斥访问;ext3文件系统的inode锁竞争);可以备份和恢复独立的分区。

2、分区表的权限:一个表最多只能有1024个分区,在5.7版本的时候可以支持8196个分区;在早期的mysql中,分区表达式必须是整数或者是返回整数的表达式,在mysql5.5中,某些场景可以直接使用列来进行分区;如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来;分区表无法使用外键约束。

3、分区表原理:分区表由多个相关的底层表实现,这个底层表也是由句柄对象标识,我们可以直接访问各个分区。存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎),分区表的索引知识在各个底层表上各自加上一个完全相同的索引。从存储引擎的角度来看,底层表和普通表没有任何不同,存储引擎也无须知道这是一个普通表还是一个分区表的一部分。

**select查询**

当查询一个分区表的时候,分区层先打开并锁住所有的底层表,优化器先判断是否可以过滤部分分区,然后再调用对应的存储引擎接口访问各个分区的数据

**insert操作**

当写入一条记录的时候,分区层先打开并锁住所有的底层表,然后确定哪个分区接受这条记录,再将记录写入对应底层表

**delete操作**

当删除一条记录时,分区层先打开并锁住所有的底层表,然后确定数据对应的分区,最后对相应底层表进行删除操作

4、分区表类型:范围分区;列表分区;列分区;hash分区;key分区;子分区。

5、如何使用分区表:全量扫描数据,不要任何索引,使用简单的分区方式存放表,不要任何索引,根据分区规则大致定位需要的数据为止,通过使用where条件将需要的数据限制在少数分区中,这种策略适用于以正常的方式访问大量数据;索引数据,并分离热点,如果数据有明显的热点,而且除了这部分数据,其他数据很少被访问到,那么可以将这部分热点数据单独放在一个分区中,让这个分区的数据能够有机会都缓存在内存中,这样查询就可以只访问一个很小的分区表,能够使用索引,也能够有效的使用缓存。

第七八章我还需要再学习先去看看官网

相关推荐

[常用工具] git基础学习笔记_git工具有哪些

添加推送信息,-m=messagegitcommit-m“添加注释”查看状态...

centos7安装部署gitlab_centos7安装git服务器

一、Gitlab介1.1gitlab信息GitLab是利用RubyonRails一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。...

太高效了!玩了这么久的Linux,居然不知道这7个终端快捷键

作为Linux用户,大家肯定在Linux终端下敲过无数的命令。有的命令很短,比如:ls、cd、pwd之类,这种命令大家毫无压力。但是,有些命令就比较长了,比如:...

提高开发速度还能保证质量的10个小窍门

养成坏习惯真是分分钟的事儿,而养成好习惯却很难。我发现,把那些对我有用的习惯写下来,能让我坚持住已经花心思养成的好习惯。...

版本管理最好用的工具,你懂多少?

版本控制(Revisioncontrol)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。...

Git回退到某个版本_git回退到某个版本详细步骤

在开发过程,有时会遇到合并代码或者合并主分支代码导致自己分支代码冲突等问题,这时我们需要回退到某个commit_id版本1,查看所有历史版本,获取git的某个历史版本id...

Kubernetes + Jenkins + Harbor 全景实战手册

Kubernetes+Jenkins+Harbor全景实战手册在现代企业级DevOps体系中,Kubernetes(K8s)、Jenkins和Harbor组成的CI/CD流水...

git常用命令整理_git常见命令

一、Git仓库完整迁移完整迁移,就是指,不仅将所有代码移植到新的仓库,而且要保留所有的commit记录1.随便找个文件夹,从原地址克隆一份裸版本库...

第三章:Git分支管理(多人协作基础)

3.1分支基本概念分支是Git最强大的功能之一,它允许你在主线之外创建独立的开发线路,互不干扰。理解分支的工作原理是掌握Git的关键。核心概念:HEAD:指向当前分支的指针...

云效Codeup怎么创建分支并进行分支管理

云效Codeup怎么创建分支并进行分支管理,分支是为了将修改记录分叉备份保存,不受其他分支的影响,所以在同一个代码库里可以同时进行多个修改。创建仓库时,会自动创建Master分支作为默认分支,后续...

git 如何删除本地和远程分支?_git怎么删除远程仓库

Git分支对于开发人员来说是一项强大的功能,但要维护干净的存储库,就需要知道如何删除过时的分支。本指南涵盖了您需要了解的有关本地和远程删除Git分支的所有信息。了解Git分支...

git 实现一份代码push到两个git地址上

一直以来想把自己的博客代码托管到github和coding上想一次更改一次push两个地址一起更新今天有空查资料实践了下本博客的github地址coding的git地址如果是Gi...

git操作:cherry-pick和rebase_git cherry-pick bad object

在编码中经常涉及到分支之间的代码同步问题,那就需要cherry-pick和rebase命令问题:如何将某个分支的多个commit合并到另一个分支,并在另一个分支只保留一个commit记录解答:假设有两...

模型文件硬塞进 Git,GitHub 直接打回原形:使用Git-LFS管理大文件

前言最近接手了一个计算机视觉项目代码是屎山就不说了,反正我也不看代码主要就是构建一下docker镜像,测试一下部署的兼容性这本来不难但是,国内服务器的网络环境实在是恶劣,需要配置各种镜像(dock...

防弹少年团田柾国《Euphoria》2周年 获世界实时趋势榜1位 恭喜呀

当天韩国时间凌晨3时左右,该曲在Twitter上以“2YearsWithEuphoria”的HashTag登上了世界趋势1位。在韩国推特实时趋势中,从上午开始到现在“Euphoria2岁”的Has...