以%开头的Like查询。可以考虑用全文索引。或利用Innodb的聚簇索引,扫索引比扫表快得多。例如:一个表有主键id,辅助索引name。现在想根据name模糊搜索 name like %end%,直接select * from table where name like %end%,会引起表的全扫描,效率低下。因为Innodb每个辅助索引中存的都是主键的值,所以可以改为select * from (select id from table
where name like %end%) a, table b where a.id = b.id; 这样子查询中因为id和name在辅助索引中满足了覆盖索引,只扫索引就可以拿到所有满足条件的id,然后根据id再去查询最终结果。
默认的隔离界别可重复读,会出现幻读的问题。select...for update可以解决幻读问题。eg:select * from data where id < 100 fro update; 会锁定id小于100的所有记录以及不存在的记录”间隙“也加锁,也级是next-key lock,所以就避免了幻读。但容易造成严重的锁等待,尽量不用,而用精确等于的条件访问更新数据。值得说明的是,当用等于条件来请求一个不存在的数据时,也会加next-key
lock。
show profiles可以查看当前线程每个查询。show profile for query + id(show profiles得到的),可以看每一步的耗时。还可以进一步在cpu io block等级别查看在使用什么资源时,耗时高。例如:show profile cpu for query + id。
select * from information_schema.optimizer_trace; 查看跟踪文件。
sql语句优化:
insert:如果单个客户端插入多条,尽量insert into test values(1,2),(3,4),(5,6)如此同时插入,减少交互
order by:btree索引是有序存储的,可以利用。所以尽量减少额外的filesort,通过索引直接返回有序数据。做法:order by与where使用相同的索引、复合索引。并且order by的字段都是升序或都是降序。 如果做不到,排序操作很多,数据较多时,适当开大sort_buffer_size让排序尽量在内存中完成,这个值是每个线程独占的,多个线程就多个buffer,注意!
group by:默认情况下group by c1, c2会对c1,c2...的所有字段排序,如果不需要刻意通过显示的加一个order by null禁止排序,提高效率。
嵌套查询:有些情况可以使用连接代替。
or:保证每个列都能用到索引,会发现mysql处理时,将每个字段分别查询后进行了UNION操作。
分页查询:limit1000,10 会排序出前1010行,最后只去10行。效率低。
利用覆盖索引:子查询先利用覆盖索引查询到满足条件的主键,再利用主键回表查找记录。eg:select name, value from data order by name limit 1000, 10; 改为 select name, value from data a inner join (select id from data order by name limit 1000, 10) b on a.id = b.id;
纪录上一次结果的最后一个排序列的值,然后:where name > lastvalue order by name limit 10; 这种方法不适合排序字段有重复值的情况,会丢纪录。
SQL提示:
USE INDEX : 让mysql参考提供的索引。eg:select * from data use index (idx_id);