cyyking 2020-06-11
一、 使用延迟查询优化 limit [offset], [rows]
经常出现类似以下的 SQL 语句:
SELECT * FROM film LIMIT 100000, 10
offset 特别大!
LIMIT 能很好地解决分页问题,但如果 offset 过大的话,会造成严重的性能问题,原因主要是因为 MySQL 每次会把一整行都扫描出来,扫描 offset 遍,找到 offset 之后会抛弃 offset 之前的数据,再从 offset 开始读取 10 条数据,显然,这样的读取方式问题。
可以通过延迟查询的方式来优化
假设有以下 SQL,有组合索引(sex, rating)
SELECT <cols> FROM profiles where sex='M' order by rating limit 100000, 10;
则上述写法可以改成如下写法
SELECT <cols>
FROM profiles
inner join
(SELECT id form FROM profiles where x.sex='M' order by rating limit 100000, 10)
as x using(id);
这里利用了覆盖索引的特性,先从覆盖索引中获取 100010 个 id,再丢充掉前 100000 条 id,保留最后 10 个 id 即可,丢掉 100000 条 id 不是什么大的开销,所以这样可以显著提升性能
二、 利用 LIMIT 1 取得唯一行
数据库引擎只要发现满足条件的一行数据则立即停止扫描,,这种情况适用于只需查找一条满足条件的数据的情况(如查询是否存在时,可以使用limit 1,而非count(*))。
三、 注意组合索引,要符合最左匹配原则才能生效
假设存在这样顺序的一个联合索引“col_1, col_2, col_3”。这时,指定条件的顺序就很重要。
SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 AND col_3 = 500;
SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 ;
SELECT * FROM SomeTable WHERE col_2 = 100 AND col_3 = 500 ;
前面两条会命中索引,第三条由于没有先匹配 col_1,导致无法命中索引, 另外如果无法保证查询条件里列的顺序与索引一致,可以考虑将联合索引 拆分为多个索引。
四、使用 LIKE 谓词时,只有前方一致的匹配才能用到索引(最左匹配原则)
SELECT * FROM SomeTable WHERE col_1 LIKE '%a';
SELECT * FROM SomeTable WHERE col_1 LIKE '%a%';
SELECT * FROM SomeTable WHERE col_1 LIKE 'a%';
上例中,只有第三条会命中索引,前面两条进行后方一致或中间一致的匹配无法命中索引
五、 简单字符串表达式
模型字符串可以使用 _ 时, 尽可能避免使用 %, 假设某一列上为 char(5)
不推荐
SELECT
first_name,
last_name,
homeroom_nbr
FROM Students
WHERE homeroom_nbr LIKE 'A-1%';
推荐
SELECT first_name, last_name
homeroom_nbr
FROM Students
WHERE homeroom_nbr LIKE 'A-1__'; --模式字符串中包含了两个下划线
六、 如有必要,使用 force index() 强制走某个索引
SELECT col from orders FORCE INDEX(order_no) WHERE order_no = 'xxxxx' ;
七、批量插入,速度更快
推荐用
INSERT INTO TABLE (id, user_id, title) VALUES (1, 2, 'a'),(2,3,'b');
不推荐用
INSERT INTO TABLE (id, user_id, title) VALUES (1, 2, 'a');
INSERT INTO TABLE (id, user_id, title) VALUES (2,3,'b');
注:本文来自 IT牧场 公众号