MySQL index optimization (1)
Simulation data
CREATE TABLE staffs(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(24) DEFAULT NULL 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());
INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES(NULL,23,'test',NOW());
ALTER TABLE staffs ADD INDEX index_staffs_nameAgePos(`name`,`age`,`pos`)
View index order
Index optimization case
- Best left prefix rule
- Full match
- Not calculated on index columns
- All failures after the scope
- Covering index more use
- Unequal use will invalidate
- Be careful when using NULL values
- Fuzzy query plus right
- String with single quotes
- Try not to use or query
Best left prefix rule
Start the query from the leftmost column of the index and do not skip the columns in the index
The filter condition to use the index must be satisfied in the order in which the index is created. Once a field is skipped, the fields after the index cannot be used
Multi-column indexes are sorted according to the first column, and then sort the second column based on the first column sorting order. If there is no first column, directly access the second column, then the second column must be none Ordinal, direct access to the following column does not use the index
Search by index
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July'
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and age = 15
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and age = 15 and pos= 'dev'
Query out of index order
EXPLAIN SELECT * FROM staffs WHERE age = 15 and pos= 'dev' --跳过第一个索引
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and pos= 'dev' -- 跳过第二个索引
Full match
The query fields can be matched in the index according to the order, and the speed is the fastest at this time.
Not calculated on index columns
Do not do any operation (calculation, function, (automatic or manual) type conversion) on the index column, which may cause the index to fail and turn to a full table scan
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July'
EXPLAIN SELECT * FROM staffs WHERE LEFT(NAME,4) = 'July' --使用函数
EXPLAIN SELECT * FROM staffs WHERE NAME = '2000'
EXPLAIN SELECT * FROM staffs WHERE NAME = 2000 --使用类型转换
All failures after the scope
After using the range query, if there are too many records in the range, the index will become invalid, because it takes too much time to map from the custom index to the primary key index, and it is not as fast as a full table scan
Suggestion: Put the index order of the fields that may be ranged in the last
Covering index more use
Using a covering index (Using index) will improve retrieval efficiency: queries that only access the index column (the index column is the same as the query column, try not to use select *)
EXPLAIN SELECT * 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'
Unequal use will invalidate
When using unequal (!= or <>), the index may become invalid
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July'
EXPLAIN SELECT * FROM staffs WHERE NAME != 'July'
EXPLAIN SELECT * FROM staffs WHERE NAME <> 'July'
The following cases in the low version of MySQL database will cause the index to fail, and I am using MySQL 8. The internal optimization of the database is carried out. Although the index is not invalid, the type is changed from ref to range, and the performance is obviously reduced.
Be careful when using NULL values
If the allowed field is empty , then
- IS NULL will not cause index failure
- IS NOT NULL will cause the index to become invalid
Fuzzy query plus right
Like query starting with a wildcard% will cause the index to fail and turn into a full table scan
EXPLAIN SELECT * FROM staffs WHERE NAME like '%July%' --左右都有通配符
EXPLAIN SELECT * FROM staffs WHERE NAME like '%July' --模糊查询加左边
EXPLAIN SELECT * FROM staffs WHERE NAME like 'July%' --模糊查询加右边
Problem: The method to solve the index like'% string%' does not take effect: use a covering index (the query field should match the index field as much as possible)
String with single quotes
EXPLAIN SELECT * FROM staffs WHERE NAME = '2000'
EXPLAIN SELECT * FROM staffs WHERE NAME = 2000 --使用类型转换
Try not to use or query
SELECT * FROM staffs WHERE NAME = 'July' OR NAME = 'z3'
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' OR NAME = 'z3'
Type becomes range after using or
Simple interview questions
create table test03(
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 test03(c1,c2,c3,c4,c5) values ('a1','a2','a3','a4','a5');
insert into test03(c1,c2,c3,c4,c5) values ('b1','b2','b3','b4','b5');
insert into test03(c1,c2,c3,c4,c5) values ('c1','c2','c3','c4','c5');
insert into test03(c1,c2,c3,c4,c5) values ('d1','d2','d3','d4','d5');
insert into test03(c1,c2,c3,c4,c5) values ('e1','e2','e3','e4','e5');
create index idx_test03_c1234 on test03(c1,c2,c3,c4);
Execution plan analysis
Case A
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1'
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2'
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c3 = 'a3'
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c3 = 'a3' and c4 = 'a4'
Case B
EXPLAIN SELECT * FROM test03 WHERE c4 = 'a4' and c3 = 'a3' and c2 = 'a2' and c1 = 'a1' --MySQL内部优化,依然使用索引
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c4 = 'a4' and c3 > 'a3'
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' and c4 = 'a4' ORDER BY c3 --c3用于排序
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c4 --出现文件排序
Case C
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c5 = 'a5' ORDER BY c2,c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c5 = 'a5' ORDER BY c3,c2
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c2,c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' and c2 = 'a2' ORDER BY c3,c2
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' ORDER BY c3,c2
Case D
My database cannot execute the following case, so there are only SQL statements. I have not verified the screenshots
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c4 = 'a4' GROUP BY c2,c3
EXPLAIN SELECT * FROM test03 WHERE c1 = 'a1' AND c4 = 'a4' GROUP BY c3,c2
- General order by is the range
- Group by is a grouping, so it must be sorted first, so there will be a temporary table
Optimization formula
The full value matches my favorite, and the leftmost prefix must be observed; the
leading brother cannot die, and the middle brother cannot be broken; the
index column is less calculated, and the range becomes invalid;
Like percent is written to the right, the covering index does not write stars;
not waiting for empty The value also has or. Use less for index failure;
VAR quotes should not be lost, and advanced SQL is not difficult!