MYSQL 表优化

一、单表优化

1、准备

create table if not EXISTS `article`(
	`id` int(10) UNSIGNED not NULL PRIMARY key AUTO_INCREMENT,
	`author_id` int(10) UNSIGNED not NULL,
	`category_id` int(10) UNSIGNED not NULL,
	`views` int(10) UNSIGNED not NULL,
	`comments` int(10) UNSIGNED not null,
	`title` VARBINARY(255) not NULL,
	`content` text not NULL
);
insert into `article`(author_id,category_id,views,comments,title,content) values 
(1,1,1,1,'1','1'),
(2,2,2,2,'2','2'),
(1,1,3,3,'3','3');

2、案例

2.1 查询category_id为1且comments>1的情况下,views最多的article_id
mysql> select * from article where category_id=1 and comments>1 order by views desc limit 1;
+----+-----------+-------------+-------+----------+-------+---------+
| id | author_id | category_id | views | comments | title | content |
+----+-----------+-------------+-------+----------+-------+---------+
|  3 |         1 |           1 |     3 |        3 | 3     | 3       |
+----+-----------+-------------+-------+----------+-------+---------+
1 row in set
mysql> explain 
select * from article where category_id=1 and comments>1 order by views desc limit 1;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
|  1 | SIMPLE      | article | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using filesort |
+----+-------------+

功能满足,但是通过explain可以看出没有使用任何优化而且还有filesort文件内排序。
开始优化:

  • 构建符合索引
mysql> create index inx_article_ccv on article
(category_id,comments,views);
mysql> explain select * from article where category_id=1 and comments>1 order by views desc limit 1;
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+---------------------------------------+
| id | select_type | table   | partitions | type  | possible_keys   | key             | key_len | ref  | rows | filtered | Extra                                 |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+---------------------------------------+
|  1 | SIMPLE      | article | NULL       | range | inx_article_ccv | inx_article_ccv | 8       | NULL |    1 |      100 | Using index condition; Using filesort |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+---------------------------------------+
1 row in set

从上面可以看到,type为range,表示使用到了范围索引而且使用到的索引为idx_article_ccv,但是还是有filesort,因为范围查找(>,<,<>,between)将会使索引失效,比如

mysql> explain select * from article where category_id=1 and comments=
1 order by views desc limit 1;
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------+------+----------+---------------------+
| id | select_type | table   | partitions | type | possible_keys   | key             | key_len | ref         | rows | filtered | Extra               |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------+------+----------+---------------------+
|  1 | SIMPLE      | article | NULL       | ref  | inx_article_ccv | inx_article_ccv | 8       | const,const |    1 |      100 | Backward index scan |
+----+-------------+---------+------------+------+-----------------+-----------------+---------+-------------+------+----------+---------------------+
1 row in set
  • 表示上一个索引不符合,接下来重新构建索引
mysql> alter table article add index idx_cv(category_id,views);
mysql> explain select * from article where category_id=1 and comments>1 order by views desc limit 1;

+----+-------------+---------+------------+------+---------------+--------+---------+-------+------+----------+----------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra                            |
+----+-------------+---------+------------+------+---------------+--------+---------+-------+------+----------+----------------------------------+
|  1 | SIMPLE      | article | NULL       | ref  | idx_cv        | idx_cv | 4       | const |    2 |    33.33 | Using where; Backward index scan |
+----+-------------+---------+------------+------+---------------+--------+---------+-------+------+----------+----------------------------------+
1 row in set

可以看到type为ref表示使用到了范围索引,而且为const毕竟=1嘛,没有文件内排序,使用到了索引idx_cv,OK,基本满足需求。

二、两表优化

1、准备

create table if not exists `class`(
	id int(10) UNSIGNED not null auto_increment,
	card int(10) UNSIGNED not null,
	PRIMARY key (id)
);
create table if not exists book (
	bookid int(10) UNSIGNED not null auto_increment,
	card int(10) UNSIGNED not null,
	primary key (bookid)
);
delimiter $$
SET GLOBAL log_bin_trust_function_creators=TRUE $$
create FUNCTION insertN(n int UNSIGNED) returns int
begin
	DECLARE i int default 0;
	WHILE i < n DO
		INSERT into class (card) values (FLOOR(1+(RAND()*20)));
		INSERT into book (card) values (FLOOR(1+(RAND()*20)));
		set i=i+1;
	end WHILE;
	return i;
end $$
delimiter ;
select insertN(30);

2、案例

mysql> explain select * from class left join book on class.card=book.card;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | class | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   30 |      100 | NULL                                               |
|  1 | SIMPLE      | book  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   30 |      100 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set

全表扫描ALL,30*30,需要优化,可是加载哪个表呢?无法判断,只能一个个试

  • 右边添加索引
mysql> explain select * from class left join book on class.card=book.card;
+----+-------------+-------+------------+------+---------------+----------+---------+--------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key      | key_len | ref                | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+----------+---------+--------------------+------+----------+-------------+
|  1 | SIMPLE      | class | NULL       | ALL  | NULL          | NULL     | NULL    | NULL               |   30 |      100 | NULL        |
|  1 | SIMPLE      | book  | NULL       | ref  | idx_card      | idx_card | 4       | advance.class.card |    1 |      100 | Using index |
+----+-------------+-------+------------+------+---------------+----------+---------+--------------------+------+----------+-------------+
2 rows in set

可以看到右表使用到了索引,使用到的索引字段为advance库的class表的card字段

mysql> alter table book drop index idx_card
;
Query OK, 0 rows affected
Records: 0  Duplicates: 0  Warnings: 0
mysql> alter table class add index idx_card (card)
;
Query OK, 0 rows affected
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from class left join book on class.card=book.card;
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | class | NULL       | index | NULL          | idx_card | 4       | NULL |   30 |      100 | Using index                                        |
|  1 | SIMPLE      | book  | NULL       | ALL   | NULL          | NULL     | NULL    | NULL |   30 |      100 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+----------------------------------------------------+
2 rows in set

可以看到添加在class左表时,左表使用到了索引,但是没有过滤作用,还是30*30,索引类型index,表示使用到了索引扫描,但是效率比ref低下。

总结

连接时,总有一端是需要全部返回的,因此搜索的是另一端所以一般在另一端添加索引比较合适。
多表连接时,也是类似,索引一般建在另一端。
当然,如果建在左端,那右连接就可以搞定,相反其他类推。
在join时,一般使用小表驱动大表,毕竟小表是要全表扫描的,所以永远小表驱动大表
优先优化最内层的循环。
保证join语句中被驱动表上join条件字段已经创建索引。
当无法保证被驱动表的join条件字段被索引且内存资源充足时,可是设置joinBuffer大点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值