数据库-性能优化篇
1、为什么要进行优化?
-
避免网站页面出现访问错误
- 由于数据库连接timeout产生页面5xx错误
- 由于慢查询造成页面无法加载
- 由于阻塞造成数据无法提交
-
增加数据库的稳定性
- 很多数据库问题都是由于低效的查询引起的
-
优化用户体验
- 流畅页面的访问速度
- 良好的网站功能体验
2、mysql数据库优化
可以从哪几个方面进行数据库的优化?
硬件->系统配置->数据库表结构->SQL及索引。成本越来越低,效果越来越高。
- SQL及索引优化
- 根据需求写出良好的SQL,并创建有效的索引,实现某一种需求可以多种写法,这时候我们就要选择一种效率最高的写法。这个时候就要了解sql优化。
- 数据库表结构优化
- 根据数据库的范式,设计表结构,表结构设计的好直接关系到写SQL语句。
- 系统配置优化
- 大多数运行在Linux机器上,如tcp连接数的限制、打开文件数的限制、安全性的限制,因此我们要对这些配置进行相应的优化。
-
硬件配置优化
选择适合数据库服务的cpu,更快的IO,更高的内存;cpu并不是越多越好,某些数据库版本有最大的限制,IO操作并不是减少阻塞。
3、慢日志查询
3.1、查看mysql的版本
select @@version;
mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 5.6.25 |
+-----------+
1 row in set (0.00 sec)
3.2、准备数据
网址:https://dev.mysql.com/doc/sakila/en/sakila-installation.html
1、通过命令行来连接数据库
shell> mysql -u root -p
2、创建表及语句执行
mysql> SOURCE C:/temp/sakila-db/sakila-schema.sql;
3、加载数据
mysql> SOURCE C:/temp/sakila-db/sakila-data.sql;
4、使用数据库
USE sakila;
5、检查创建的表
SHOW TABLES;
+----------------------------+
| Tables_in_sakila |
+----------------------------+
| actor |
| actor_info |
| address |
| category |
| city |
| country |
| customer |
| customer_list |
| film |
| film_actor |
| film_category |
| film_list |
| film_text |
| inventory |
| language |
| nicer_but_slower_film_list |
| payment |
| rental |
| sales_by_film_category |
| sales_by_store |
| staff |
| staff_list |
| store |
+----------------------------+
6、检验数据是否加载进去
mysql> select count(*) from film;
+----------+
| count(*) |
+----------+
| 1000 |
+----------+
1 row in set (0.00 sec)
3.3、发现有问题的SQL
慢日志查询的主要功能就是,记录sql语句中超过设定的时间阈值的查询语句。例如,一条查询sql语句,我们设置的阈值为1s,当这条查询语句的执行时间超过了1s,则将被写入到慢查询配置的日志中.
3.3.1、检查慢查日志是否开启:
show variables like '%query%';
其中需要关注的配置项为:
slow_query_log:是否开启慢日志查询功能.
slow_query_log_file:慢日志查询的记录文件
long_query_time:慢日志查询的时间阈值
3.3.2、查看所有日志的变量信息
开启慢查日志:
// 开启慢日志
set global slow_query_log=on;
// 设置慢查询日志的时间阈值为0 (原来是10)
set global long_query_time=0;
在mysql操作中: select * from film;
window打开sql_query_log_file,它的位置可以通过 show variables like '%query%';查找
3.3.3、MySQL慢查日志的存储格式
说明:
1、# Time: 180526 1:06:54 -------à查询的执行时间
2、# User@Host: root[root] @ localhost [] Id: 4 -------à执行sql的主机信息
3、# Query_time: 0.000401 Lock_time: 0.000105 Rows_sent: 2 Rows_examined: 2-------àSQL的执行信息:
Query_time:SQL的查询时间
Lock_time:锁定时间
Rows_sent:所发送的行数
Rows_examined:锁扫描的行数
4、SET timestamp=1527268014; -------àSQL执行时间
5、select * from staff; -------àSQL的执行内容
3.4 慢查日志的分析工具
先不学了。
- mysqldumpslow
- pt-query-digest
通过分析,发现有问题的sql:
- 查询次数多,并且时间长
- IO大
- 索引命中率不高的SQL
4、SQL及索引的优化
1、什么是索引?
索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
数据库使用索引以找到特定值,然后顺指针找到包含该值的行。在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。索引的建立是表中比较有指向性的字段,相当于目录,比如说行政区域代码,同一个地域的行政区域代码都是相同的,那么给这一列加上索引,避免让它重复扫描,从而达到优化的目的!
2、如何创建索引
在执行CREATE TABLE语句时可以创建索引,也可以单独用CREATE INDEX或ALTER TABLE来为表增加索引。
1、ALTER TABLE
ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADDINDEX index_name (column_list)
ALTER TABLE table_name ADDUNIQUE (column_list)
ALTER TABLE table_name ADDPRIMARY KEY (column_list)
说明:其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。索引名index_name可选,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引。
2、CREATE INDEX
CREATE INDEX可对表增加普通索引或UNIQUE索引。
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
说明:table_name、index_name和column_list具有与ALTER TABLE语句中相同的含义,索引名不可选。另外,不能用CREATE INDEX语句创建PRIMARY KEY索引。
3、索引类型
在创建索引时,可以规定索引能否包含重复值。如果不包含,则索引应该创建为PRIMARY KEY或UNIQUE索引。对于单列惟一性索引,这保证单列不包含重复的值。对于多列惟一性索引,保证多个值的组合不重复。
PRIMARY KEY索引和UNIQUE索引非常类似。
事实上,PRIMARY KEY索引仅是一个具有名称PRIMARY的UNIQUE索引。这表示一个表只能包含一个PRIMARY KEY,因为一个表中不可能具有两个同名的索引。
下面的SQL语句对students表在sid上添加PRIMARYKEY索引。
ALTER TABLE students ADDPRIMARY KEY (sid)
4、删除索引
可利用ALTER TABLE或DROPINDEX语句来删除索引。类似于CREATE INDEX语句,DROPINDEX可以在ALTER TABLE内部作为一条语句处理,语法如下。
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROPINDEX index_name
ALTER TABLE table_name DROPPRIMARY KEY
其中,前两条语句是等价的,删除掉table_name中的索引index_name。
第3条语句只在删除PRIMARYKEY索引时使用,因为一个表只可能有一个PRIMARY KEY索引,因此不需要指定索引名。如果没有创建PRIMARY KEY索引,但表具有一个或多个UNIQUE索引,则MySQL将删除第一个UNIQUE索引。
如果从表中删除了某列,则索引会受到影响。对于多列组合的索引,如果删除其中的某列,则该列也会从索引中删除。如果删除组成索引的所有列,则整个索引将被删除。
5、查看索引
6、什么情况下,使用索引了?
- 表的主关键字
- 自动建立唯一索引
- 表的字段唯一约束
- 直接条件查询的字段(在SQL中用于条件约束的字段)
- 查询中与其它表关联的字段
- 查询中排序的字段(排序的字段如果通过索引去访问那将大大提高排序速度)
- 查询中统计或分组统计的字段
- 表记录太少(如果一个表只有5条记录,采用索引去访问记录的话,那首先需访问索引表,再通过索引表访问数据表,一般索引表与数据表不在同一个数据块)
- 经常插入、删除、修改的表(对一些经常处理的业务表应在查询允许的情况下尽量减少索引)
- 数据重复且分布平均的表字段(假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。)
- 经常和主字段一块查询但主字段索引值比较多的表字段
- 对千万级MySQL数据库建立索引的事项及提高性能的手段
3、如何选择合适的列建立索引
-
在where从句,group by从句,order by从句,on从句中虚线的列添加索引
-
索引字段越小越好(因为数据库数据存储单位是以“页”为单位的,数据存储的越多,IO也会越大)
-
离散度大的列放到联合索引的前面(取值多,重复少)
select count(distinct name) from stu;
4、索引优化SQL的方法
1、索引的维护及优化(重复及冗余索引)
增加索引会有利于查询效率,但会降低insert,update,delete的效率,但实际上往往不是这样的,过多的索引会不但会影响使用效率,同时会影响查询效率,这是由于数据库进行查询分析时,首先要选择使用哪一个索引进行查询,如果索引过多,分析过程就会越慢,这样同样的减少查询的效率,因此我们要知道如何增加,有时候要知道维护和删除不需要的索引
2、如何找到重复和冗余的索引
重复索引:重复索引是指相同的列以相同的顺序简历的同类型的索引,如下表中的 primary key和ID列上的索引就是重复索引
冗余索引:冗余索引是指多个索引的前缀列相同,或是在联合索引中包含了主键的索引。
说明:对于innodb来说,每一个索引后面,实际上都会包含主键,这时候我们建立的联合索引,又人为的把主键包含进去,那么这个时候就是一个冗余索引。
5、注意事项
设计好MySql的索引可以让你的数据库飞起来,大大的提高数据库效率。设计MySql索引的时候有一下几点注意:
1,创建索引
对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。
但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。
2,复合索引
比如有一条语句是这样的:select * from users where area=’beijing’ and age=22;
如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age,salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。
因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
3,索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
4,使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
5,排序的索引问题
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
6,like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
7,不要在列上进行运算
select * from users whereYEAR(adddate)
8,不使用NOT IN和操作
NOTIN和操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替,id3则可使用id>3 or id
5、MYSQL数据库设计
命名规范:数字+字母+下划线,通常命名为user_name
核心原则:
- 不在数据库做运算
- 控制列数量
- 平衡范式和冗余(效率优先;往往牺牲范式)
- 拒绝大SQL语句,拒绝大事务,拒绝大批量
字段原则:
- 最好用数值型
- 避免使用NULL字段
- 少用text,尽量使用varchar代替