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

Insert picture description here


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'

Insert picture description here

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' -- 跳过第二个索引

Insert picture description here

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 --使用类型转换

Insert picture description here

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

Insert picture description here

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'

Insert picture description here

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.
Insert picture description here

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
    Insert picture description here

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%'  --模糊查询加右边

Insert picture description here
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 --使用类型转换

Insert picture description here

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
Insert picture description here

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'

Insert picture description here

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 --出现文件排序

Insert picture description here

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

Insert picture description here

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

Insert picture description here

  • General order by is the range
  • Group by is a grouping, so it must be sorted first, so there will be a temporary table

Insert picture description here


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!

Guess you like

Origin blog.csdn.net/single_0910/article/details/113860669