Optimization-优化

概念

数据库优化是一个没有最好,只有更好的话题,一切脱离业务的优化都是耍流氓。优化涉及多个角度,多个级别,取决于你的工作角色(开发者,DBA或者两者的结合),可以在单个SQL语句,整个应用程序,单个数据库服务器,数据库集群等级别进行优化。

Optimization-优化_第1张图片

原则

  • 具体问题具体分析,一些特定的业务场景并不适合套用普遍使用的原则
  • 多数优化都是用空间换取时间,尤其适用于并发量大、数据量大的互联网业务

角度

SQL语句

对于数据库应用程序来讲,SQL语句实现了其核心业务逻辑,也是开发人员最应该入手的优化角度。数据库操纵语言(Data Manipulation Language, DML)是我们主要优化的对象,它又可以分为读,写两大类。在大多数应用程序中,查询(SELECT)语句的频率要远高于更新(INSERT,UPDATE,DELETE)语句,因此查询语句的优化至关重要。

查询优化主要考虑以下情况:

  • 让SELECT … WHERE查询速度更快,首先考虑为WHERE子句中的条件列添加索引,能够轻易将查询性能提升几个数量级。索引对于引用不同表的查询(如JOIN)尤为重要,可以使用EXPLAN语句来分析SELECT查询使用了哪些索引。
  • 尽量避免查询中的全表扫描,尤其是大的数据表。
  • 避免复杂的,难以理解的SELECT查询语句(如大量的多表连接),尤其是大的数据表。
  • 适当调节数据库服务缓存使用内存空间的大小,重复的查询会运行更快。

这里概括了查询优化的基本情况,实际上可以在细节上优化的点有很多,具体可以查看数据库对应的操作手册,如MySQL查询优化,这里不再一一列举。

索引

虽然建立索引是提升查询性能的最佳方式,但是过多无必要的索引会浪费空间与选择索引时间,同样也会影响insert,update,delete的性能(需要更新索引)。

索引优化可以考虑以下情况:

  • 独立列,在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。
//无法使用actor_id列的索引
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;
  • 多列索引:在需要使用多个列作为条件查询时,多列索引比单列索引性能更好。
SELECT film_id, actor_ id FROM sakila.film_actor
WhERE actor_id = 1 AND film_id = 1;
  • 索引列顺序:选择性最强的索引列放到最前面。选择性是指:不重复的索引值和记录总数的比值,最大值为1,此时每个记录都有唯一索引与之对应。选择性越高,查询效率越高。
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,
COUNT(*)
FROM payment;

//查询结果,customer_id的选择性比staff_id更高,因此最好把customer_id 列放在多列索引的前面。
staff_id_selectivity: 0.0001
customer_id_selectivity: 0.0373
COUNT(*): 16049
  • 前缀索引对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。前缀长度的选取需要根据索引选择性来确定。
  • 覆盖索引:索引包含所有需要查询的字段的值。

服务器

从数据库服务器的角度进行优化,进行系统配置,通常由DBA完成。

  • 系统因素:如果拥有足够的RAM,可以移除所有的swap devices(或者说虚拟内存),有些操作系统即使在物理内存充足的情况下也会使用虚拟内存。

  • 磁盘I/O:磁盘I/O通常是数据库的性能瓶颈,总的原则是减少磁盘I/O次数,比如可以调整缓存区,或者更换性能更好的磁盘设备。

方法

查询优化可能是最常做的数据库优化,对于MySQL来讲,它提供了一个EXPLAIN命令,可以对SELECT语句进行分析,以供开发人员针对性的优化。
EXPLAIN 用法十分简单,在 SELECT 语句前加上 EXPLAIN 即可,如:

EXPLAIN SELECT * FROM actor WHERE last_name = 'WOOD'

查询结果大致如下:

mysql> EXPLAIN SELECT * FROM actor WHERE last_name = 'WOOD' ;
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys       | key                 | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | actor | NULL       | ref  | idx_actor_last_name | idx_actor_last_name | 137     | const |    2 |      100 | NULL  |
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------+
1 row in set

各列含义如下:

id SELECT 查询的标识符. 每个 SELECT 都会自动分配一个唯一的标识符
select_type SELECT 查询的类型
table 查询的是哪个表
partitions 匹配的分区
type join 类型
possible_keys 此次查询中可能选用的索引
key 此次查询中确切使用到的索引
ref 哪个字段或常数与 key 一起被使用
rows 显示此查询一共扫描了多少行. 这个是一个估计值
filtered 表示此查询条件所过滤的数据的百分比
extra 额外的信息

参考资料

  1. Chapter 8 Optimization
  2. MySQL 性能优化神器 Explain 使用分析

你可能感兴趣的:(☆Ops)