热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

实践(1)--MySQL性能优化

MySQL教程栏目为大家介绍:MySQL性能优化。

案例2:

假定学生关系表为 Student (学号、姓名、年龄、所在学院、学院地点、学院电话),关键字为单一关键字“学号”,因为存在如下决定关系:

(学号)-> (姓名、年龄、所在学院、学院地点、学院电话) 

即存在非关键字段“学院地点”、“学院电话”对关键字段“学号”的传递函数依赖。 它也会存在数据冗余,更新异常、插入异常和删除异常的情况。正确应把学生关系表分为如下两个表:

  • 学生:(学号、姓名、年龄、所在学院)
  • 学院:(学院、地点、电话)

范式化优缺点

范式化的优点:

  1. 重复数据少,不冗余;
  2. 维护更新快;
  3. 范式化的表更小,可在内存中运行。

范式化的缺点:

查询的时候经常需要很多关联,增加查询的代价。也可能使一些索引策略失效,因为范式化将列放在不同的表中,而这些列在一个表中本可以属于同一个索引。

反范式化的优缺点

反范式化的优点:

  1. 避免关联,几乎所有数据可以在一张表中显示。
  2. 可以设计有效的索引。

反范式化的缺点:

冗余数据多,更小维护麻烦,删除数据时也容易丢失重要信息。

数据表设计的建议

没有冗余的数据库设计可以做到,但是,没有冗余的数据库未必是最好的数据库,有时为列提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。

另外,《阿里巴巴Java开发手册》,数据库的表设计允许适当冗余,以提升SQL查询的性能,避免表的关联查询。

适度冗余,减少join的关联

冗余更新频率不高,但是查询频率极高的字段。如订单中的商品名称、微博发帖中的用户昵称。

SQL语句优化

SQL优化的一般步骤

  1. 通过show status命令了解各种SQL的执行频率;
  2. 定位执行效率较低的SQL语句-(重点select);
  3. 通过explain分析低效率的SQL;
  4. 确定问题并采取相应的优化措施。
-- select语句分类SelectDml数据操作语言(insert update delete)
dtl 数据事物语言(commit rollback savepoint)Ddl数据定义语言(create alter drop..)
Dcl(数据控制语言) grant revoke-- Show status 常用命令--查询本次会话Show session status like 'com_%';     //show session status like 'Com_select'--查询全局Show global status like 'com_%';-- 给某个用户授权grant all privileges on *.* to 'abc'@'%';--为什么这样授权 'abc' 表示用户名  '@' 表示host, 查看一下mysql->user表就知道了--回收权限revoke all on *.* from 'abc'@'%';--刷新权限[也可以不写]flush privileges; 

SQL语句优化-show参数

MySQL客户端连接成功后,通过使用 show [session|global] status 命令可以提供服务器状态信息。其中的session来表示当前的连接的统计结果,global来表示自数据库上次启动至今的统计结果。默认是session级别的。

show status like 'Com_%'; 

其中, Com_XXX 表示 XXX 语句所执行的次数。 重点注意:Com_select,Com_insert,Com_update,Com_delete 通过这几个参数,可以了解到当前数据库的应用是以插入更新为主还是以查询操作为主,以及各类的SQL大致的执行比例是多少。

还有几个常用的参数便于用户了解数据库的基本情况。Connections:试图连接MySQL服务器的次数Uptime:服务器工作的时间(单位秒)Slow_queries:慢查询的次数 (默认是慢查询时间10s)

show status like 'Connections';show status like 'Uptime';show status like 'Slow_queries'; 

查询MySQL的慢查询时间

show variables like 'long_query_time'; 

修改MySQL慢查询时间

set long_query_time=2; 

SQL语句优化-定位慢查询

上面我们介绍了获取MySQL数据库的一些运行状态是如何查询

  • 比如当前MySQL运行的时间: show status like 'Uptime';
  • 一共执行了多少次select/update/delete.. /show status like 'Com_%';
  • 当前连接数

定位慢查询

如何从一个项目中快速定位执行速度慢的语句(定位慢查询)

show variables like '%query%'; 

注意:

  1. 如何打开慢查询 : SET GLOBAL slow_query_log = ON;
  2. 将默认时间改为1S: SET GLOBAL long_query_time = 1;

(设置完需要重新连接数据库,PS:仅在这里改的话,当再次重启数据库服务时,所有设置又会自动恢复成默认值,永久改变需去my.ini中改)

SQL语句优化-Explain工具

使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈 在 select 语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL。

注意:如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表中

Explain分析示例

DROP TABLE IF EXISTS `actor`; 
CREATE TABLE `actor` (`id` int(11) NOT NULL,`name` varchar(45) DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `actor` (`id`,`name`,`update_time`) VALUES (1,'a','2020-09-16 14:26:11'), (2,'b','2020-09-16 14:26:11'), (3,'c','2020-09-16 14:26:11');DROP TABLE IF EXISTS` film`; 
CREATE TABLE`film`(`id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`),KEY `idx_name` (`name`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `film`(`id`,`name`) VALUES (3,'film0'),(1,'film1'),(2,'film2');DROP TABLE IF EXISTS `film_actor`;CREATE TABLE`film_actor`(`id` int(11) NOT NULL,`film_id` int(11) NOT NULL,`actor_id` int(11) NOT NULL,`remark` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),KEY `idx_film_actor_id` (`film_id`,`actor_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO`film_actor`(`id`,`film_id`,`actor_id`)VALUES(1,1,1), (2,1,2),(3,2,1); 
explain select * from actor; 
#关闭mysql5.7新特性对衍 生表的合并优化set session optimizer_switch='derived_merge=off'; 
 
#还原默认配置set session optimizer_switch='derived_merge=on'; 
 
  • union :在 union 中的第二个和随后的 select
explain select 1 union all select 1; 

table 列

这一列表示 explain 的一行正在访问哪个表。 当 from 子句中有子查询时,table列是 格式,表示当前查询依赖 id=N 的查 询,于是先执行 id=N 的查询。 当有 union 时,UNION RESULT 的 table 列的值为,1和2表示参与 union 的 select 行id。

type 列

这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。

依次从最优到最差分别为:

system > const > eq_ref > ref > range > index > ALL 

一般来说,得保证查询达到 range 级别,最好达到 ref

NULL:MySQL 能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表。

explain select min(id) from film; 

possible_keys 列

这一列显示查询可能使用哪些索引来查找。 explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。 如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查 where 子句看是否可以创造一个适当的索引来提高查询性能,然后用 explain 查看效果。

key 列

这一列显示mysql实际采用哪个索引来优化对该表的访问。 如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索 引,在查询中使用 force indexignore index

key_len 列

这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些 列。 举例来说,film_actor的联合索引 idx_film_actor_id 由 film_id 和 actor_id 两个int列组成, 并且每个int是4字节。通过结果中的key_len=4可推断出查询使用了第一个列:film_id列来执 行索引查找。

explain select * from film_actor where film_id = 2; 

key_len计算规则如下: 字符串

  • char(n):n字节长度
  • varchar(n):2字节存储字符串长度,如果是utf-8,则长度 3n +2

数值类型

  • tinyint:1字节
  • smallint:2字节
  • int:4字节
  • bigint:8字节

时间类型

  • date:3字节
  • timestamp:4字节
  • datetime:8字节

如果字段允许为 NULL,需要1字节记录是否为 NULL

索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。

ref 列

这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常 量),字段名(例:film.id)

rows 列

这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。

Extra 列

这一列展示的是额外信息。常见的重要值如下:

(1)Using index :使用覆盖索引

explain select film_id from film_actor where film_id = 1; 

SQL语句优化-索引最佳实践

# 示例表CREATE TABLE`employees`(`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
PRIMARY KEY (`id`), KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
 )ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记录表'; 
INSERT INTO employees(name,age,position,hire_time)VALUES('ZhangSan',23,'Manager',NOW());INSERT INTO employees(name,age,position,hire_time)VALUES('HanMeimei', 23,'dev',NOW());INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW()); 

全值匹配

EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan'; 
  • 如果不能使用覆盖索引则可能需要借助搜索引擎

字符串不加单引号索引失效

EXPLAIN SELECT * FROM employees WHERE name = '1000'; 
EXPLAIN SELECT * FROM employees WHERE name = 1000; 

以上就是实践(1)--MySQL性能优化的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • PHP中Smarty模板引擎自定义函数详解
    本文详细介绍了如何在PHP的Smarty模板引擎中自定义函数,并通过具体示例演示了这些函数的使用方法和应用场景。适合PHP后端开发者学习。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 解决ADODB连接Access时出现80004005错误的方法
    本文详细介绍了如何解决在使用ADODB连接Access数据库时遇到的80004005错误,包括错误原因分析和具体的解决步骤。 ... [详细]
  • 本文详细解析了MySQL中常见的几种错误,并提供了具体的解决方法,帮助开发者快速定位和解决问题。 ... [详细]
  • 搭建个人博客:WordPress安装详解
    计划建立个人博客来分享生活与工作的见解和经验,选择WordPress是因为它专为博客设计,功能强大且易于使用。 ... [详细]
  • Java连接MySQL数据库的方法及测试示例
    本文详细介绍了如何安装MySQL数据库,并通过Java编程语言实现与MySQL数据库的连接,包括环境搭建、数据库创建以及简单的查询操作。 ... [详细]
  • 本文详细介绍了如何使用SQL*Plus连接Oracle数据库以及使用MySQL客户端连接MySQL数据库的方法,包括基本命令和具体操作步骤。 ... [详细]
  • 本文详细探讨了如何根据不同的应用场景选择合适的PHP版本,包括多版本切换技巧、稳定性分析及针对WordPress等特定平台的版本建议。 ... [详细]
  • C/C++ 应用程序的安装与卸载解决方案
    本文介绍了如何使用Inno Setup来创建C/C++应用程序的安装程序,包括自动检测并安装所需的运行库,确保应用能够顺利安装和卸载。 ... [详细]
  • 本文探讨了使用Python实现监控信息收集的方法,涵盖从基础的日志记录到复杂的系统运维解决方案,旨在帮助开发者和运维人员提升工作效率。 ... [详细]
  • 本文提供了处理WordPress网站中出现过多重定向问题的方法,包括检查DNS配置、安装SSL证书以及解决数据库连接错误等步骤。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 随着Linux操作系统的广泛使用,确保用户账户及系统安全变得尤为重要。用户密码的复杂性直接关系到系统的整体安全性。本文将详细介绍如何在CentOS服务器上自定义密码规则,以增强系统的安全性。 ... [详细]
  • 本文详细介绍如何安装和配置DedeCMS的移动端站点,包括新版本安装、老版本升级、模板适配以及必要的代码修改,以确保移动站点的正常运行。 ... [详细]
  • JavaScript 跨域解决方案详解
    本文详细介绍了JavaScript在不同域之间进行数据传输或通信的技术,包括使用JSONP、修改document.domain、利用window.name以及HTML5的postMessage方法等跨域解决方案。 ... [详细]
author-avatar
威哥028_438
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有