您现在的位置是:网站首页> 编程资料编程资料
MySQL提升大量数据查询效率的优化神器_Mysql_
2023-05-26
576人已围观
简介 MySQL提升大量数据查询效率的优化神器_Mysql_
前言
在应用的的开发过程中,由于初期数据量小,开发人员写 SQL 语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多 SQL 语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的 SQL 语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化.
为什么这么说呢?因为在MySQL查询语句中,语法比较的通用吗,要想得到一个数据集可以使用不同的查询语句!
例如我们需要查询一个数据表有多少行数据集?
1、暴力搜索
select count(*) from data;
这样虽然也可以达到效果,但是用 "SELECT * " 数据库需要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
增大网络开销,* 有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增长。特别是MySQL和应用程序不在同一台机器,这种开销非常明显。
2、限定字段查询
select count(id) from data;
这里的id是一个递增的序列,查询效果确实有所提升。
MySQL的优化方式有很多,大致我们可以从以下几点来优化MySQL:
- 从设计上优化
- 从查询上优化
- 从索引上优化
- 从存储上优化
查看SQL执行频率
MySQL 客户端连接成功后,通过 show [session|global] status 命令可以查看服务器状态信息。通过查看状态信息可以查看对当前数据库的主要操作类型。
--下面的命令显示了当前 session 中所有统计参数的值 show session status like 'Com_______'; -- 查看当前会话统计结果 show global status like 'Com_______'; -- 查看自数据库上次启动至今统计结果 show status like 'Innodb_rows_%'; -- 查看针对Innodb引擎的统计结果

定位低效率执行SQL
可以通过以下两种方式定位执行效率较低的 SQL 语句。
慢查询日志 : 通过慢查询日志定位那些执行效率较低的 SQL 语句。
show processlist:该命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看 SQL 的执行情况,同时对一些锁表操作进行优化。
-- 查看慢日志配置信息 show variables like '%slow_query_log%'; -- 开启慢日志查询 set global slow_query_log=1; -- 查看慢日志记录SQL的最低阈值时间 show variables like 'long_query_time%'; -- 修改慢日志记录SQL的最低阈值时间 set global long_query_time=4;
show processlist;

- 1) id列,用户登录mysql时,系统分配的"connection_id",可以使用函数connection_id()查看
- 2) user列,显示当前用户。如果不是root,这个命令就只显示用户权限范围的sql语句
- 3) host列,显示这个语句是从哪个ip的哪个端口上发的,可以用来跟踪出现问题语句的用户
- 4) db列,显示这个进程目前连接的是哪个数据库
- 5) command列,显示当前连接的执行的命令,一般取值为休眠(sleep),查询(query),连接(connect)等
- 6) time列,显示这个状态持续的时间,单位是秒
- 7) state列,显示使用当前连接的sql语句的状态,很重要的列。state描述的是语句执行中的某一个状态。一个sql语句,以查询为例,可能需要经过copying to tmp table、sorting result、sending data等状态才可以完成
- 8) info列,显示这个sql语句,是判断问题语句的一个重要依据
explain分析执行计划
通过以上步骤查询到效率低的 SQL 语句后,可以通过 EXPLAIN命令获取 MySQL如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。
-- 准备测试数据 create database mydb13_optimize; use mydb13_optimize;
执行sql脚本sql_optimize.sql添加数据
explain select * from user where uid = 1;


id 字段是 select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。id 情况有三种:
1、id 相同表示加载表的顺序是从上到下
explain select * from user u, user_role ur, role r where u.uid = ur.uid and ur.rid = r.rid ;

2、 id 不同id值越大,优先级越高,越先被执行。
explain select * from role where rid = (select rid from user_role where uid = (select uid from user where uname = '张飞'))

3、 id 有相同,也有不同,同时存在。id相同的可以认为是一组,从上往下顺序执行;在所有的组中,id的值越大,优先级越高,越先执行。

表示 SELECT 的类型,常见的取值,如下表所示:

type 显示的是访问类型,是较为重要的一个指标,可取值为:

结果值从最好到最坏以此是:system > const > eq_ref > ref > range > index > ALL

其他的额外的执行计划信息,在该列展示 。

Mysql从5.0.37版本开始增加了对 show profiles 和 show profile 语句的支持。show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。
通过 have_profiling 参数,能够看到当前MySQL是否支持profile:
select @@have_profiling; set profiling=1; -- 开启profiling 开关;
通过profile,我们能够更清楚地了解SQL执行的过程。首先,我们可以执行一系列的操作
show databases; use mydb13_optimize; show tables; select * from user where id < 2; select count(*) from user;
执行完上述命令之后,再执行show profiles 指令, 来查看SQL语句执行的耗时:
show profiles;

通过show profile for query query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间:
show profile for query 8;

在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io 、context switch、page faults等明细类型类查看MySQL在使用什么资源上耗费了过高的时间。例如,选择查看CPU的耗费时间 :
show profile cpu for query 133;

在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io 、context switch、page faults等明细类型类查看MySQL在使用什么资源上耗费了过高的时间。例如,选择查看CPU的耗费时间 :

trace分析优化器执行计划
MySQL5.6提供了对SQL的跟踪trace, 通过trace文件能够进一步了解为什么优化器选择A计划, 而不是选择B计划

SET optimizer_trace="enabled=on",end_markers_in_json=on; set optimizer_trace_max_mem_size=1000000;
执行SQL语句 :
select * from user where uid < 2;
最后, 检查information_schema.optimizer_trace就可以知道MySQL是如何执行SQL的 :
select * from information_schema.optimizer_trace\G;

使用索引优化
索引是数据库优化最常用也是最重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。
create table `tb_seller` ( `sellerid` varchar (100), `name` varchar (100), `nickname` varchar (50), `password` varchar (60), `status` varchar (1), `address` varchar (100), `createtime` datetime, primary key(`sellerid`) );
索引是数据库优化最常用也是最重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00'); insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00'); insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('huawei','华为科技有限公司','华为小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00'); insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itcast','传智播客教育科技有限公司','传智播客','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00'); insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itheima','黑马程序员','黑马程序员','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00'); insert into `tb_seller` (`sellerid`, `name`, `nickname`, `p
相关内容
- mysql查看表结构的三种方法总结_Mysql_
- MySQL中正则表达式(REGEXP)使用详解_Mysql_
- MySQL实现字段分割一行转多行的示例代码_Mysql_
- mysql拆分字符串作为查询条件的示例代码_Mysql_
- mysql全面解析json/数组_Mysql_
- MySQL中字段类型为longtext的值导出后显示二进制串方式_Mysql_
- MySql中的longtext字段的返回问题及解决_Mysql_
- Mysql如何对json数据进行查询及修改_Mysql_
- mysql5.6 解析JSON字符串方式(支持复杂的嵌套格式)_Mysql_
- MySql 查询符合条件的最新数据行_Mysql_
点击排行
本栏推荐
