本文摘自:http://www.phpfensi.com/mysql/20141008/6772.html
本文章来给大家介绍一篇关于mysql中使用order by 和limit查询变慢解决办法,因为在mysql分页利用limit来操作,同时排序也需要使用了order by ,所以经常会两者同是使用到,但是如果数据量大的话就会碰到查询很慢很慢,下面我来给大家介绍解决办法。
先来看一下测试性能,代码如下:
- 1.显示行 0 - 9 (10 总计, 查询花费 32.4894 秒)
- 2.SQL 查询: SELECT *
- 3.FROM tables
- 4.WHERE m_id
- 5.IN ( 50, 49 )
- 6.ORDER BY id DESC
- 7.LIMIT 10
- 显示行 0 - 9 (10 总计, 查询花费 32.4894 秒)
- SQL 查询: SELECT *
- FROM tables
- WHERE m_id
- IN ( 50, 49 )
- ORDER BY id DESC
- LIMIT 10
- 1.显示行 0 - 9 (10 总计, 查询花费 0.0497 秒)
- 2.SQL 查询: SELECT *
- 3.FROM tables
- 4.WHERE m_id
- 5.IN ( 50, 49 )
- 6.LIMIT 10
- 显示行 0 - 9 (10 总计, 查询花费 0.0497 秒)
- SQL 查询: SELECT *
- FROM tables
- WHERE m_id
- IN ( 50, 49 )
- LIMIT 10
- 1.显示行 0 - 29 (1,333 总计, 查询花费 0.0068 秒)
- 2.SQL 查询: SELECT *
- 3.FROM tables
- 4.WHERE m_id
- 5.IN ( 50, 49 )
- 6.ORDER BY id DESC
- 7.
- 显示行 0 - 29 (1,333 总计, 查询花费 0.0068 秒)
- SQL 查询: SELECT *
- FROM tables
- WHERE m_id
- IN ( 50, 49 )
- ORDER BY id DESC
- 1.显示行 0 - 29 (1,333 总计, 查询花费 0.12秒)
- 2.SQL 查询: SELECT *
- 3.FROM tables
- 4.WHERE m_id
- 5.IN ( 50, 49 )
- 6.ORDER BY m_id, id DESC
- 7.
- 显示行 0 - 29 (1,333 总计, 查询花费 0.12秒)
- SQL 查询: SELECT *
- FROM tables
- WHERE m_id
- IN ( 50, 49 )
- ORDER BY m_id, id DESC
- 1.显示行 0 - 29 (1,333 总计, 查询花费 0.0068 秒)
- 2.SQL 查询: SELECT *
- 3.FROM tables
- 4.FORCE INDEX ( m_id ) //强制索引
- 5.WHERE m_id
- 6.IN ( 50, 49 )
- 7.ORDER BY id DESC
- 8.
上面的办法如果数据量上千万级也是会很慢的,有可能查询一次到10秒或更长.
优化limit和offset,MySQL的limit工作原理就是先读取n条记录,然后抛弃前n条,读m条想要的,所以n越大,性能会越差,代码如下:
优化前SQL:SELECT * FROM member ORDER BY last_active LIMIT 50,5
优化后SQL:SELECT * FROM member INNER JOIN (SELECT member_id FROM member ORDER BY last_active LIMIT 50,5) USING (member_id)
分别在于,优化前的SQL需要更多I/O浪费,因为先读索引,再读数据,然后抛弃无需的行,而优化后的SQL(子查询那条)只读索引(Cover index)就可以了,然后通过member_id读取需要的列.
对mysql服务器优化也可以提升性能了.
1、只返回需要的数据
返回数据到客户端至少需要数据库提取数据、网络传输数据、客户端接收数据以及客户端处理数据等环节,如果返回不需要的数据,就会增加服务器、网络和客户端的无效劳动,其害处是显而易见的,避免这类事件需要注意:
A、横向来看,不要写SELECT *的语句,而是选择你需要的字段.
B、纵向来看,合理写WHERE子句,不要写没有WHERE的SQL语句.
C、注意SELECT INTO后的WHERE子句,因为SELECT INTO把数据插入到临时表,这个过程会锁定一些系统表,如果这个WHERE子句返回的数据过多或者速度太慢,会造成系统表长期锁定,诸塞其他进程.
D、对于聚合查询,可以用HAVING子句进一步限定返回的行.
2、尽量少做重复的工作
这一点和上一点的目的是一样的,就是尽量减少无效工作,但是这一点的侧重点在客户端程序,需要注意的如下:
A、控制同一语句的多次执行,特别是一些基础数据的多次执行是很多程序员很少注意的。
B、减少多次的数据转换,也许需要数据转换是设计的问题,但是减少次数是程序员可以做到的。
C、杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销。
D、合并对同一表同一条件的多次UPDATE,比如代码如下:
这两个语句应该合并成以下一个语句,代码如下:
- UPDATE EMPLOYEE SET FNAME=’HAIWER’,LNAME=’YANG’
- WHERE EMP_ID=’ VPA30890F’ --phpfensi.com
E、UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能相同,但是性能差别是很大的.
F、不要写一些没有意义的查询,比如:SELECT * FROM EMPLOYEE WHERE 1=2
3、注意事务和锁
事务是数据库应用中和重要的工具,它有原子性、一致性、隔离性、持久性这四个属性,很多操作我们都需要利用事务来保证数据的正确性。在使用事务中我们需要做到尽量避免死锁、尽量减少阻塞。具体以下方面需要特别注意.
A、事务操作过程要尽量小,能拆分的事务要拆分开来。
B、事务操作过程不应该有交互,因为交互等待的时候,事务并未结束,可能锁定了很多资源。
C、事务操作过程要按同一顺序访问对象。
D、提高事务中每个语句的效率,利用索引和其他方法提高每个语句的效率可以有效地减少整个事务的执行时间。
E、尽量不要指定锁类型和索引,SQL SERVER允许我们自己指定语句使用的锁类型和索引,但是一般情况下,SQLSERVER优化器选择的锁类型和索引是在当前数据量和查询条件下是最优的,我们指定的可能只是在目前情况下更有,但是数据量和数据分布在将来是会变化的。
F、查询时可以用较低的隔离级别,特别是报表查询的时候,可以选择最低的隔离级别