数据库优化有好多种:
1》实例优化
数据库优化目标
根据角色的不同,数据库优化分为以下几个目标:
业务角度(关键用户): 减少用户页面响应时间
数据库角度(开发): 减少数据库SQL响应时间
数据库服务器角度(运维): 充分使用数据库服务器物理资源 减少数据库服务器CPU使用率 减少数据库服务器IO使用率 减少数据库服务器内存使用率
数据库优化指标
SQL平均响应时间变短
优化前:数据库平均响应时间500ms
优化目标:数据库平均响应时间200ms
数据库服务器CPU占用率变少
优化前:数据库高峰期CPU使用率70%
优化目标:数据库高峰期CPU使用率50%
数据库服务器IO使用率变低
优化前:数据库IO WAIT为30%
优化目标:数据库IO WAIT低于10%
数据库实例优化
数据库实例优化遵循三句口诀:日志不能小、缓存足够大、连接要够用。
数据库事务提交后需要将事务对数据页的修改刷( fsync)到磁盘上,才能保证数据的持久性。这个刷盘,是一个随机写,性能较低,如果每次事务提交都要刷盘,会极大影响数据库的性能。数据库在架构设计中都会采用如下两个优化手法:
先将事务写到日志文件RedoLog(WAL),将随机写优化成顺序写
加一层缓存结构Buffer,将每次写优化成批量写
所以日志跟缓存对数据库实例尤其重要。而连接如果不够用,数据库会直接抛出异常,系统无法访问
数据库参数优化
主流数据库架构都有如下的共同点:
数据缓存
SQL解析区
排序内存
REDO及UNDO
锁、LATCH、MUTEX
监听及连接
文件读写性能
接下来我们根据不同的数据库调整参数以使数据库达到最佳性能。
ORACLE
参数分类 参数名 参数值 备注
数据缓存 SGA_TAGET、MEMORY_TARGET 物理内存70-80% 越大越好
数据缓存 DB_CACHE_SIZE 物理内存70-80% 越大越好
SQL解析 SHARED_POOL_SIZE 4-16G 不建议设置过大
监听及连接 PROCESSES、SESSIONS、OPEN_CURSORS 根据业务需求设置 一般为业务预估连接数的120%
其他 SESSION_CACHED_CURSORS 大于200 软软解析
MYSQL(INNODB)
参数分类 参数名 参数值 备注
数据缓存 INNODB_BUFFER_POOL_SIZE 物理内存50-80% 一般来说越大性能越好
日志相关 Innodb_log_buffer_size 16-32M 根据运行情况调整
日志相关 sync_binlog 1、100、0 1安全性最好
监听及连接 max_connections 根据业务情况调整 可以预留一部分值
文件读写性能 innodb_flush_log_at_trx_commit 2 安全和性能的折中考虑
其他 wait_timeout,interactive_timeout 28800 避免应用连接定时中断
POSTGRES
参数分类 参数名 参数值 备注
数据缓存 SHARED_BUFFERS 物理内存10-25%
数据缓存 CACHE_BUFFER_SIZE 物理内存50-60%
日志相关 wal_buffer 8-64M 不建议设置过大过小
监听及连接 max_connections 根据业务情况调整 一般为业务预估连接数的120%
其他 maintenance_work_mem 512M或更大
其他 work_mem 8-16M 原始配置1M过小
其他 checkpoint_segments 32或者更大
达梦数据库
参数分类 参数名 参数值 备注
数据缓存 MEMROY_TARGET、MEMROY_POOL 物理内存90%
数据缓存 BUFFER 物理内存60% 数据缓存
数据缓存 MAX_BUFFER 物理内存70% 最大数据缓存
监听及连接 max_sessions 根据业务需求设置 一般为业务预估连接数的120%
总结
数据库的优化手法太多太多,有换磁盘阵列升级硬件,有改写SQL脚本添加索引,还有数据库参数调整优化性能,甚至还可以调整数据库架构。本文从数据库本身参数进行调优,大家根据上面几张表中的参数进行调整基本能达到数据库最佳性能的80%。
2》SQL优化,大多数的情况都是SQL优化
判断SQL是否有问题时可以通过两个表象进行判断:
系统级别表象
CPU消耗严重
IO等待严重
页面响应时间过长
应用的日志出现超时等错误
可以使用sar命令,top命令查看当前系统状态。
也可以通过Prometheus、Grafana等监控工具观察系统状态。
冗长的SQL都好理解,一段SQL太长阅读性肯定会差,而且出现问题的频率肯定会更高。更进一步判断SQL问题就得从执行计划入手,如下所示:
执行计划告诉我们本次查询走了全表扫描Type=ALL,rows很大(9950400)基本可以判断这是一段"有味道"的SQL。
获取问题SQL
不同数据库有不同的获取方法,以下为目前主流数据库的慢查询SQL获取工具
MySQL
慢查询日志
测试工具loadrunner
Percona公司的ptquery等工具
SQL编写技巧
SQL编写有以下几个通用的技巧:
• 合理使用索引
索引少了查询慢;索引多了占用空间大,执行增删改语句的时候需要动态维护索引,影响性能 选择率高(重复值少)且被where频繁引用需要建立B树索引;
一般join列需要建立索引;复杂文档类型查询采用全文索引效率更好;索引的建立要在查询和DML性能之间取得平衡;复合索引创建时要注意基于非前导列查询的情况
• 使用UNION ALL替代UNION
UNION ALL的执行效率比UNION高,UNION执行时需要排重;UNION需要对数据进行排序
• 避免select * 写法
执行SQL时优化器需要将 * 转成具体的列;每次查询都要回表,不能走覆盖索引。
• JOIN字段建议建立索引
一般JOIN字段都提前加上索引
• 避免复杂SQL语句
提升可阅读性;避免慢查询的概率;可以转换成多个短查询,用业务端处理
• 避免where 1=1写法
• 避免order by rand()类似写法
RAND()导致数据列被多次扫描
SQL优化
执行计划
完成SQL优化一定要先读执行计划,执行计划会告诉你哪些地方效率低,哪里可以需要优化。我们以MYSQL为例,看看执行计划是什么。(每个数据库的执行计划都不一样,需要自行了解)explain sql
字段 解释
id 每个被独立执行的操作标识,标识对象被操作的顺序,id值越大,先被执行,如果相同,执行顺序从上到下
select_type 查询中每个select 字句的类型
table 被操作的对象名称,通常是表名,但有其他格式
partitions 匹配的分区信息(对于非分区表值为NULL)
type 连接操作的类型
possible_keys 可能用到的索引
key 优化器实际使用的索引(最重要的列) 从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL。当出现ALL时表示当前SQL出现了“坏味道”
key_len 被优化器选定的索引键长度,单位是字节
ref 表示本行被操作对象的参照对象,无参照对象为NULL
rows 查询执行所扫描的元组个数(对于innodb,此值为估计值)
filtered 条件表上数据被过滤的元组个数百分比
extra 执行计划的重要补充信息,当此列出现Using filesort , Using temporary 字样时就要小心了,很可能SQL语句需要优化
接下来我们用一段实际优化案例来说明SQL优化的过程及优化技巧。
优化案例
表结构
CREATE TABLE `a`
(
`id` int(11) NOT NULLAUTO_INCREMENT,
`seller_id` bigint(20) DEFAULT NULL,
`seller_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`gmt_create` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `b`
(
`id` int(11) NOT NULLAUTO_INCREMENT,
`seller_name` varchar(100) DEFAULT NULL,
`user_id` varchar(50) DEFAULT NULL,
`user_name` varchar(100) DEFAULT NULL,
`sales` bigint(20) DEFAULT NULL,
`gmt_create` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `c`
(
`id` int(11) NOT NULLAUTO_INCREMENT,
`user_id` varchar(50) DEFAULT NULL,
`order_id` varchar(100) DEFAULT NULL,
`state` bigint(20) DEFAULT NULL,
`gmt_create` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
);
三张表关联,查询当前用户在当前时间前后10个小时的订单情况,并根据订单创建时间升序排列,具体SQL如下
select a.seller_id,
a.seller_name,
b.user_name,
c.state
from a,
b,
c
where a.seller_name = b.seller_name
and b.user_id = c.user_id
and c.user_id = 17
and a.gmt_create
BETWEEN DATE_ADD(NOW(), INTERVAL – 600 MINUTE)
AND DATE_ADD(NOW(), INTERVAL 600 MINUTE)
order by a.gmt_create;
查看数据量
原执行时间
原执行计划
初步优化思路
SQL中 where条件字段类型要跟表结构一致,表中user_id 为varchar(50)类型,实际SQL用的int类型,存在隐式转换,也未添加索引。将b和c表user_id 字段改成int类型。
因存在b表和c表关联,将b和c表user_id创建索引
因存在a表和b表关联,将a和b表seller_name字段创建索引
利用复合索引消除临时表和排序
初步优化SQL
alter table b modify `user_id` int(10) DEFAULT NULL;
alter table c modify `user_id` int(10) DEFAULT NULL;
alter table c add index `idx_user_id`(`user_id`);
alter table b add index `idx_user_id_sell_name`(`user_id`,`seller_name`);
alter table a add index `idx_sellname_gmt_sellid`(`gmt_create`,`seller_name`,`seller_id`);
查看优化后执行时间
查看优化后执行计划
查看warnings信息
继续优化alter table a modify "gmt_create" datetime DEFAULT NULL;
查看执行时间
查看执行计划
总结
查看执行计划 explain
如果有告警信息,查看告警信息 show warnings;
查看SQL涉及的表结构和索引信息
根据执行计划,思考可能的优化点
按照可能的优化点执行表结构变更、增加索引、SQL改写等操作
查看优化后的执行时间和执行计划
如果优化效果不明显,重复第四步操作
原文链接:https://blog.csdn.net/jianzhang11/article/details/102867120