首页 > 数据库 > 数据库开发技术 > MySQL性能优化(第二部分)
SELECT *
FROM employee
WHERE emp_id = 5;



如果定义了主键,InnoDB使用主键聚集数据;
如果没有定义主键,InnoDB使用第一个非空的UNIQUE索引聚集数据;
如果没有主键和可用的UNIQUE索引,InnoDB使用一个隐藏的内部ID字段聚集数据。


SELECT count(DISTINCT emp_name)/count(*) emp_name_sel,
count(DISTINCT sex)/count(*) sex_sel
FROM employee;
emp_name_sel|sex_sel|
------------+-------+
1.0000| 0.0800|
(col1)
(col1, col2)
(col1, col2, col3)
WHERE col1 = val1 AND col2 = val2 AND col3 = val3
WHERE col1 = val1 AND col2 = val2
WHERE col1 = val1
WHERE col1 = val1 AND col2 BETWEEN val2 AND val3
WHERE col1 BETWEEN val1 AND val2
WHERE col1 LIKE ‘ABC%’
SELECT count(DISTINCT LEFT(email,3))/count(DISTINCT email) left3,
count(DISTINCT LEFT(email,4))/count(DISTINCT email) left4,
count(DISTINCT LEFT(email,5))/count(DISTINCT email) left5,
count(DISTINCT LEFT(email,6))/count(DISTINCT email) left6
FROM employee;
left3 |left4 |left5 |left6 |
------+------+------+------+
0.6000|0.7200|0.9200|1.0000|
CREATE INDEX idx_employee_email ON employee(email(6));
explain
select *
from employee
where lower(email) = lower('ZhangFei@shuguo.com');
Name |Value |
-------------+-----------+
id |1 |
select_type |SIMPLE |
table |employee |
partitions | |
type |ALL |
possible_keys| |
key | |
key_len | |
ref | |
rows |25 |
filtered |100.0 |
Extra |Using where|
create unique index uk_emp_email_lower on employee( (lower(email)) );
analyze table test;
explain
select *
from employee
where lower(email) = lower('ZhangFei@shuguo.com');
Name |Value |
-------------+------------------+
id |1 |
select_type |SIMPLE |
table |employee |
partitions | |
type |const |
possible_keys|uk_emp_email_lower|
key |uk_emp_email_lower|
key_len |403 |
ref |const |
rows |1 |
filtered |100.0 |
Extra | |
CREATE TABLE employees (
data JSON,
INDEX idx ((CAST(data->>"$.name" AS CHAR(30)) COLLATE utf8mb4_bin))
);
INSERT INTO employees VALUES
('{ "name": "james", "salary": 9000 }'),
('{ "name": "James", "salary": 10000 }'),
('{ "name": "Mary", "salary": 12000 }'),
('{ "name": "Peter", "salary": 8000 }');
SELECT * FROM employees WHERE data->>'$.name' = 'James';
CREATE TABLE t (
id INT AUTO_INCREMENT PRIMARY KEY, c1 INT, c2 INT,
INDEX idx1 (c1 ASC, c2 ASC),
INDEX idx2 (c1 ASC, c2 DESC),
INDEX idx3 (c1 DESC, c2 ASC),
INDEX idx4 (c1 DESC, c2 DESC)
);
explain
select *
from t
ORDER BY c1 ASC, c2 DESC;
Name |Value |
-------------+-----------+
id |1 |
select_type |SIMPLE |
table |t |
partitions | |
type |index |
possible_keys| |
key |idx2 |
key_len |10 |
ref | |
rows |1 |
filtered |100.0 |
Extra |Using index|
CREATE TABLE t1 (
i INT,
j INT,
k INT,
INDEX i_idx (i) INVISIBLE
) ENGINE = InnoDB;
CREATE INDEX j_idx ON t1 (j) INVISIBLE;
ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;
explain
select emp_id, dept_id
from employee
where dept_id = 5;
Name |Value |
-------------+------------+
id |1 |
select_type |SIMPLE |
table |employee |
partitions | |
type |ref |
possible_keys|idx_emp_dept|
key |idx_emp_dept|
key_len |4 |
ref |const |
rows |8 |
filtered |100.0 |
Extra |Using index |
EXPLAIN
SELECT *
FROM employee e
ORDER BY emp_name;
Name |Value |
-------------+--------------+
id |1 |
select_type |SIMPLE |
table |e |
partitions | |
type |ALL |
possible_keys| |
key | |
key_len | |
ref | |
rows |25 |
filtered |100.0 |
Extra |Using filesort|
EXPLAIN
SELECT emp_id, emp_name
FROM employee e
ORDER BY emp_name;
Name |Value |
-------------+------------+
id |1 |
select_type |SIMPLE |
table |e |
partitions | |
type |index |
possible_keys| |
key |idx_emp_name|
key_len |202 |
ref | |
rows |25 |
filtered |100.0 |
Extra |Using index |
WHERE col1 = val1 ORDER BY col2, col3
WHERE col1 = val1 ORDER BY col2 DESC
WHERE col1 BETWEEN val1 AND val2 ORDER BY col1, col2
WHERE col1 = val1 ORDER BY col2 DESC, col3
WHERE col1 = val1 ORDER BY col3
WHERE col1 BETWEEN val1 AND val2 ORDER BY col2, col3
CREATE TABLE t (
id INT AUTO_INCREMENT PRIMARY KEY,
c1 INT UNIQUE,
c2 INT,
INDEX idx_pk (id),
INDEX idx1 (c1)
);
索引将相关的数据存储在一起,减少需要扫描的数据量,获得一星;
索引中的数据顺序和查询排序顺序一致,避免排序操作,获得二星;
索引包含了查询所需的全部字段,避免随机IO,获得三星。
CREATE TABLE t (
id INT AUTO_INCREMENT PRIMARY KEY,
c1 INT,
c2 INT,
INDEX idx1 (c1, c2)
);
EXPLAIN
SELECT *
FROM t
WHERE c1>100
ORDER BY c1, c2;
Name |Value |
-------------+------------------------+
id |1 |
select_type |SIMPLE |
table |t |
partitions | |
type |index |
possible_keys|idx1 |
key |idx1 |
key_len |10 |
ref | |
rows |1 |
filtered |100.0 |
Extra |Using where; Using index|
首先,索引需要占用磁盘空间。索引独立于数据而存在,过多的索引会导致占用大量的空间。
其次,进行DML操作时,也需要对索引进行维护;维护索引有时候比修改数据更加耗时。
经常出现在WHERE条件或者ORDER BY中的字段创建索引,可以避免全表扫描和额外的排序操作;
多表连接查询的关联字段或者外键涉及的字段,可以避免全表扫描和外键级联操作导致的锁表;
查询中的GROUP BY分组操作字段。
原文作者:SQL编程思想;如有侵权,请联系管理员删除。