1. 建表sql语句
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'),
(3,3,3,3,'3','3');
2. 没建索引之前
SELECT * FROM article WHERE category_id=1 AND comments>1 ORDER BY views DESC LIMIT 1
3. 建了idx_article_ccv索引之后
CREATE INDEX idx_article_ccv ON `article` (category_id,comments,views)
4. 建了idx_article_cv索引之后
CREATE INDEX idx_article_cv ON `article` (category_id,views)
CREATE TABLE IF NOT EXISTS `class`(
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
);
CREATE TABLE IF NOT EXISTS `book`(
`bookid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
);
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
1. 没建索引之前
SELECT * FROM book LEFT JOIN class ON book.card = class.card
EXPLAIN SELECT * FROM book LEFT JOIN class ON book.card = class.card
2. 在左表card字段建索引
CREATE INDEX Y ON book(card)
EXPLAIN SELECT * FROM book LEFT JOIN class ON book.card = class.card
3. 在右表card字段建索引
CREATE INDEX X ON class(card)
EXPLAIN SELECT * FROM book LEFT JOIN class ON book.card = class.card
4. 总结
所以说,如果是左连接
的话,就将索引建立在右表
上;如果是右连接
的话,就将索引建立在左表
上。
在这个案例上使用到的表是在上一个案例上添加了一张表。
CREATE TABLE IF NOT EXISTS `phone`(
`phoneid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
)ENGINE = INNODB;
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO phone(card)VALUES(FLOOR(1+(RAND()*20)));
1. 没建索引之前
SELECT * FROM class LEFT JOIN book ON class.card = book.card LEFT JOIN phone ON book.card = phone.card
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card=book.card LEFT JOIN phone ON book.card=phone.card;
2. 在book和phone表上建了索引之后
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card=book.card LEFT JOIN phone ON book.card=phone.card;
“永远用小结果集驱动大的结果集”
。优先优化NestedLoop的内层循环
。不要太吝啬JoinBuffer的设置
。
CREATE TABLE staffs(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(24)NOT NULL DEFAULT'' COMMENT'姓名',
`age` INT NOT NULL DEFAULT 0 COMMENT'年龄',
`pos` VARCHAR(20) NOT NULL DEFAULT'' COMMENT'职位',
`add_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT'入职时间'
)CHARSET utf8 COMMENT'员工记录表';
insert into staffs(NAME,age,pos,add_time) values('z3',22,'manager',NOW());
insert into staffs(NAME,age,pos,add_time) values('July',23,'dev',NOW());
insert into staffs(NAME,age,pos,add_time) values('2000',23,'dev',NOW());
全值匹配:就是查询字段在索引中可以全部匹配到
。
1.第一条sql语句的性能分析
SELECT * FROM staffs WHERE NAME='July'
EXPLAIN SELECT * FROM staffs WHERE NAME='July'
2.第二条sql语句的性能分析
SELECT * FROM staffs WHERE NAME='July' AND age = 23
EXPLAIN SELECT * FROM staffs WHERE NAME='July' AND age = 23
3.第三条sql语句的性能分析
SELECT * FROM staffs WHERE NAME='July' AND age = 23 AND pos = 'dev'
EXPLAIN SELECT * FROM staffs WHERE NAME='July' AND age = 23 AND pos = 'dev'
最佳左前缀法则:如果索引了多列,要遵守最佳左前缀法则。指的是擦查询从索引的最左列开始并且不跳过索引中的列
。
1.第一条sql语句的性能分析
SELECT * FROM staffs WHERE pos = 'dev'
EXPLAIN SELECT * FROM staffs WHERE pos = 'dev'
2.第二条sql语句的性能分析
SELECT * FROM staffs WHERE age = 23 AND pos = 'dev'
EXPLAIN SELECT * FROM staffs WHERE age = 23 AND pos = 'dev'
3.第三条sql语句的性能分析
SELECT * FROM staffs WHERE NAME = 'July' AND pos = 'dev'
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' AND pos = 'dev'
4. 最佳左前缀法则总结
带头大哥不能死,中间兄弟不能断
不在索引列上做任何操作(计算、函数、(自动or手动)类型转换)
,会导致索引失效而转向全表扫描。
1.第一条sql语句的性能分析
SELECT * FROM staffs WHERE NAME='July'
EXPLAIN SELECT * FROM staffs WHERE NAME='July'
2.第二条sql语句的性能分析(在索引列使用了函数)
SELECT * FROM staffs WHERE LEFT(NAME,4) = 'July'
EXPLAIN SELECT * FROM staffs WHERE LEFT(NAME,4) = 'July'
3.口诀总结
索引列上少计算
但自己这一列的索引有效
。1.第一条sql语句的性能分析
SELECT * FROM staffs WHERE NAME = 'July' AND age > 22 AND pos='dev'
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' AND age > 22 AND pos='dev'
2.多条sql语句的性能分析对比
3.口诀总结
范围之后全失效
只访问索引的查询(索引列和查询列一致)
),减少select *
。查询列的字段名和字段个数和索引列的字段名和个数完全一致,或者索引列的字段名和个数真包含查询列的字段名和字段个数
。以上两种情况都属于覆盖索引。1.第一条sql语句的性能分析
SELECT NAME,age,pos FROM staffs WHERE NAME = 'July' AND age = 23 AND pos='dev'
EXPLAIN SELECT NAME,age,pos FROM staffs WHERE NAME = 'July' AND age = 23 AND pos='dev'
2.多条sql语句的性能分析对比
使用不等于(!= 或 <>)的时候无法使用索引会导致全表扫描
。1.第一条sql语句的性能分析
SELECT * FROM staffs WHERE NAME != 'July'
EXPLAIN SELECT * FROM staffs WHERE NAME != 'July'
1.第一条sql语句的性能分析
SELECT * FROM staffs WHERE NAME IS NOT NULL
EXPLAIN SELECT * FROM staffs WHERE NAME IS NOT NULL
2.多条sql语句的性能分析对比
建表和插入数据的sql语句
CREATE TABLE `tbl_user`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`age`INT(11) DEFAULT NULL,
`email` VARCHAR(20) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('1aa1',21,'a@163.com');
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('2aa2',23,'b@163.com');
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('3aa3',24,'c@163.com');
INSERT INTO tbl_user(`name`,`age`,`email`)VALUES('4aa4',26,'d@163.com');
创建索引的sql语句
CREATE INDEX idx_name_age ON tbl_user(NAME,age)
1.第一条sql语句的性能分析
SELECT * FROM tbl_user WHERE NAME LIKE '%aa%'
EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE '%aa%'
2.第二条sql语句的性能分析
SELECT * FROM tbl_user WHERE NAME LIKE '%aa'
EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE '%aa'
3.第三条sql语句的性能分析
SELECT * FROM tbl_user WHERE NAME LIKE 'aa%'
EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE 'aa%'
4.口诀总结
Like百分写最右
5.出现的问题
我们需要使用覆盖索引
。就是我们查询的字段需要被在相应的索引字段中。这样我们可以提高查询速率。举例说明
EXPLAIN SELECT NAME FROM tbl_user WHERE NAME LIKE '%aa%'
EXPLAIN SELECT age FROM tbl_user WHERE NAME LIKE '%aa%'
EXPLAIN SELECT id,NAME,age FROM tbl_user WHERE NAME LIKE '%aa%'
EXPLAIN SELECT NAME,age FROM tbl_user WHERE NAME LIKE '%aa%'
EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE '%aa%'
EXPLAIN SELECT id,NAME,age,email FROM tbl_user WHERE NAME LIKE '%aa%'
相关的字符串不加单引号会导致其字段的索引失效
。这样会导致隐式的类型转换
,所以会导致全表扫描。1.第一条sql语句的性能分析
SELECT * FROM tbl_user WHERE NAME = '1aa1' OR NAME = '2aa2'
EXPLAIN SELECT * FROM tbl_user WHERE NAME = '1aa1' OR NAME = '2aa2'
优化口诀总结
create table test(
id int primary key not null auto_increment,
c1 char(10),
c2 char(10),
c3 char(10),
c4 char(10),
c5 char(10));
insert into test(c1,c2,c3,c4,c5) values ('a1','a2','a3','a4','a5');
insert into test(c1,c2,c3,c4,c5) values ('b1','b2','b3','b4','b5');
insert into test(c1,c2,c3,c4,c5) values ('c1','c2','c3','c4','c5');
insert into test(c1,c2,c3,c4,c5) values ('d1','d2','d3','d4','d5');
insert into test(c1,c2,c3,c4,c5) values ('e1','e2','e3','e4','e5');
create index idx_test03_c1234 on test03(c1,c2,c3,c4);
mysql> select * from test;
+----+------+------+------+------+------+
| id | c1 | c2 | c3 | c4 | c5 |
+----+------+------+------+------+------+
| 1 | a1 | a2 | a3 | a4 | a5 |
| 2 | b1 | b2 | b3 | b4 | b5 |
| 3 | c1 | c2 | c3 | c4 | c5 |
| 4 | d1 | d2 | d3 | d4 | d5 |
| 5 | e1 | e2 | e3 | e4 | e5 |
+----+------+------+------+------+------+
5 rows in set (0.00 sec)
# 创建索引
mysql> create index idx_test_c1234 on test(c1,c2,c3,c4);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
# 查询索引
mysql> show index from test;
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test | 0 | PRIMARY | 1 | id | A | 5 | NULL | NULL | | BTREE | | |
| test | 1 | idx_test_c1234 | 1 | c1 | A | 5 | NULL | NULL | YES | BTREE | | |
| test | 1 | idx_test_c1234 | 2 | c2 | A | 5 | NULL | NULL | YES | BTREE | | |
| test | 1 | idx_test_c1234 | 3 | c3 | A | 5 | NULL | NULL | YES | BTREE | | |
| test | 1 | idx_test_c1234 | 4 | c4 | A | 5 | NULL | NULL | YES | BTREE | | |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.00 se
explain select * from test where c1 = 'a1';
explain select * from test where c1 = 'a1' and c2 = 'a2';
explain select * from test where c1 = 'a1' and c2 = 'a2' and c3 = 'a3';
explain select * from test where c1 = 'a1' and c2 = 'a2' and c3 = 'a3' and c4 = 'a4';
explain select * from test where c1 = 'a1' and c2 = 'a2' and c3 = 'a3' and c4 = 'a4';
explain select * from test where c1 = 'a1' and c3 = 'a3' and c2 = 'a2' and c4 = 'a4';
explain select * from test where c4 = 'a4' and c3 = 'a3' and c2 = 'a2' and c1 = 'a1';
explain select * from test where c1 = 'a1' and c2 = 'a2' and c3 > 'a3' and c4 = 'a4';
explain select * from test where c1 = 'a1' and c2 = 'a2' and c4 > 'a4' and c3 = 'a3';
explain select * from test where c1 = 'a1' and c2 = 'a2' and c4 = 'a4' order by c3;
explain select * from test where c1 = 'a1' and c2 = 'a2' order by c3;
explain select * from test where c1 = 'a1' and c2 = 'a2' order by c4;
explain select * from test where c1 = 'a1' and c5 = 'a5' order by c2,c3;
explain select * from test where c1 = 'a1' and c5 = 'a5' order by c3,c2;
explain select * from test where c1 = 'a1' and c2 = 'a2' order by c2,c3;
explain select * from test where c1 = 'a1' and c2 = 'a2' and c5 = 'a5' order by c2,c3;
explain select * from test where c1 = 'a1' and c2 = 'a2' and c5 = 'a5' order by c3,c2;
explain select * from test where c1 = 'a1' and c5 = 'a5' order by c3,c2;
explain select * from test where c1 = 'a1' and c4 = 'a4' group by c2,c3;
explain select * from test where c1 = 'a1' and c4 = 'a4' group by c3,c2;
order by
给定的是个范围;group by
一般都需要进行排序,会产生临时表;query
过滤性更好的字段;query
中过滤性最好的字段在索引字段顺序中越靠前越好;query
中 WHERE
子句中更多字段的索引;query
写法来达到选择合适索引的目的;版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_56727438/article/details/121713056
内容来源于网络,如有侵权,请联系作者删除!