目标
了解什么是优化
掌握优化查询的方法
掌握优化数据库结构的方法
掌握优化mysql服务器的方法
什么是优化
合理安排资源,调整系统参数使得mysql运行更快,更节省资源
优化是多方面的,包括查询、更新、服务器等
原则: 减少系统瓶颈,减少资源占用,增加系统的反应速度
数据库性能参数
使用 show status 语句查看mysql数据库的性能参数
* show status like 'value'
常用的参数: slow_queries 慢查询次数 com_(CRUD) 操作的次数 Uptime 上线时间
查询优化
1. explain
在mysql中可以使用explain查看sql的执行计划,用法: explain select * from tb_item,
explain 查询语句
参数说明:
id: select 识别码。这是select查询序号,不重要
select_type:表示SELECT语句的类型
1. SIMPLE 表示简单查询,其中不包含连接查询和子查询
2. PRIMARY 表示主查询 或者是 最外围的查询语句
3. UNION 表示连接查询union 后的查询 ,就像下面的历史表查询
explain select * from ( select * from red_packet union all select * from red_packet_his) m
4. DEPENDENT UNION
UNION中的第二个或后面的SELECT语句,取决于外面的查询。
5. UNION RESULT
连接查询的结果
6. SUBQUERY
子查询中的第一个select语句
explain select * from red_packet where send_aip_no = (
select send_aip_no from red_packet where gain_type = '1'
)
7、 DEPENDENT SUBQUERY
子查询中的第1个SELECT语句,取决于外面的查询。
8、 DERIVED
SELECT (FROM 子句的子查询)
type:表示表的连接类型(重要)
以下的连接类型的顺序是从最佳到最差
1. system
表仅有一行,这是const类型的特例,平时不会出现,只是特例
2. const
数据表只有一行匹配到,查询速度很快,常用于主键索引或者唯一索引的查询,可以理解为const的查询是最优
3. eq_ref
mysql手册是这样说的:"对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用于使用=比较带索引的列。
select * from user_info,order_info where user_id = source_order;
也就是 连接查询中的连接语句中的列,用到了唯一索引或者是主键索引
4. ref
查询条件的索引既不是primary key 也不是 unique, ref 用于 = 或<或>操作符带索引的列
select * from user_info,order_info where user_num = source_order; 比如user_num是索引列,
这个查询的执行计划的type就是ref
5、 ref_or_null
该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
上面这五种情况都是很理想的索引使用情况。
6、 index_merge
该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
7、 unique_subquery
该类型替换了下面形式的IN子查询的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
8、 index_subquery
该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range
只检索给定范围的行,使用一个索引来选择行
10、index
该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
11、ALL
对于每个来自于先前的表的行组合,进行完整的表扫描。(全表扫描,性能最差)
possible_key
表示mysql能使用哪个索引在该表中找到行,如果改列为null,说明没有使用索引,可以对
该列创建索引提高性能。
key
显示mysql实际查询中使用到的索引,如果没有用到,显示为null
可以强制使用索引或忽略索引:
select * from tb_user ignore index(age) where age<10; ---强制忽略索引
select * from tb_user use index(age) where age<10; ---强制使用索引
key_len
显示mysql决定使用的键的长度,如果没有用到键,则是null
ref
显示使用哪个列或常数与key一起从表中选择行
rows
mysql执行时,扫描的行数
extra(显示mysql解决查询的详细信息)
该列包含MySQL解决查询的详细信息
- Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
- Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
- range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
- Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。
- Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
- Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。
- Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
- Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
- Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。
–直接创建索引
CREATE INDEX index_name ON table(column(length))
–修改表结构的方式添加索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length))
–创建表的时候同时创建索引
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX index_name (title(length))
)
–删除索引
DROP INDEX index_name ON table
–创建唯一索引
CREATE UNIQUE INDEX indexName ON table(column(length))
–修改表结构
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))
–创建表的时候直接指定
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
UNIQUE indexName (title(length))
);
其速度比把资料输入现有FULLTEXT索引的速度更为快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
–创建表的适合添加全文索引
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
FULLTEXT (content)
);
–修改表结构添加全文索引
ALTER TABLE article ADD FULLTEXT index_content(content)
–直接创建索引
CREATE FULLTEXT INDEX index_content ON article(content)
2.建立索引可以大大提高检索的数据,以及减少表的检索行数
3.在表连接的连接条件 可以加速表与表直接的相连
4.在分组和排序字句进行数据检索,可以减少查询时间中 分组 和 排序时所消耗的时间(数据库的记录会重新排序)
5.建立索引,在查询中使用索引 可以提高性能
2.索引文件会占用物理空间,除了数据表需要占用物理空间之外,每一个索引还会占用一定的物理空间
3.当对表的数据进行 INSERT,UPDATE,DELETE 的时候,索引也要动态的维护,这样就会降低数据的维护速度,(建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快)
假如索引列TYPE有5个键值,如果有1万条数据,那么 WHERE TYPE = 1将访问表中的2000个数据块。
再加上访问索引块,一共要访问大于200个的数据块。
如果全表扫描,假设10条数据一个数据块,那么只需访问1000个数据块,既然全表扫描访问的数据块
少一些,肯定就不会利用索引了
禁用索引
对于非空表,插入记录时,MySQL会根据表的索引对插入的记录建立索引。如果插入大量数据,建立索引会降低插入数据速度。
为了解决这个问题,可以在批量插入数据之前禁用索引,数据插入完成后再开启索引。
禁用索引的语句:
ALTER TABLE table_name DISABLE KEYS
开启索引语句:
ALTER TABLE table_name ENABLE KEYS
对于空表批量插入数据,则不需要进行操作,因为MyISAM引擎的表是在导入数据后才建立索引。
禁用唯一性检查
唯一性校验会降低插入记录的速度,可以在插入记录之前禁用唯一性检查,插入数据完成后再开启。
禁用唯一性检查的语句:SET UNIQUE_CHECKS = 0;
开启唯一性检查的语句:SET UNIQUE_CHECKS = 1;
批量插入数据
插入数据时,可以使用一条INSERT语句插入一条数据,也可以插入多条数据。
第二种方式的插入速度比第一种方式快。
使用LOAD DATA INFILE
当需要批量导入数据时,使用LOAD DATA INFILE语句比INSERT语句插入速度快很多。
InnoDB
禁用唯一性检查
用法和MyISAM一样
禁用外键检查
插入数据之前执行禁止对外键的检查,数据插入完成后再恢复,可以提供插入速度。
禁用:SET foreign_key_checks = 0;
开启:SET foreign_key_checks = 1;
禁止自动提交
插入数据之前执行禁止事务的自动提交,数据插入完成后再恢复,可以提供插入速度。
禁用:SET autocommit = 0;
开启:SET autocommit = 1;