🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 一个复杂查询还是多个简单的查询 设计查询的时候需要考虑的一个问题是,是否将一个复杂查询分成多个简单的查询 在传统的实现中,总是强调需要数据库层完成尽可能多的工作,这样做的逻辑在于以前总是认为网络通信,查询解析和优化是一件代价很高的事情 但是这样对于mysql并不适用,mysql设计上让连接和断开都是很轻量级的 mysql内部每秒能够扫描内存中百万行数据,相比之下,mysql响应数据给客户端就慢的多了.在其他条件相同的时候,使用尽可能少的查询当然更好.但是有时候,一个大查询分成多个小查询还是很有必要的 # 切分查询 有时候对于一个大查询我们需要"分而治之",将大查询切分成小查询,每个查询功能完全一样,只完成一小部分,每次只返回一部分查询结果 删除旧的数据就是一个很好的例子.定期清除大量数据时,如果用一个大的语句一次性完成的话,则可能需要一次锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞很多小的但重要的查询. 将一个大的DELETE语句切分成多个较小的查询可以尽可能小的影响mysql性能,同时还可以减少mysql复制的延迟.例如,我们需要每个月运行下面的查询 ~~~ mysql> delete from message where created < DATE_SUB(NOW(), INTERVAL 3 MONTH); ~~~ 那么可以用类似下面的办法来完成同样的工作 ~~~ rows_affected = 0 do { rows_affected = do_query( "DELETE FROM messages where created < DATE_SUB(NOW(), INTERVAL 3 MONTH) limit 10000") } while rows_affected>0 ~~~ 一次删除一万行数据对服务器来说是一个比较高效而且对服务器(Percona Toolkit中pt-archiver工具就可以安全简单的完成这类工作)影响也最小的做法(如果是事务型引擎,很多时候小事务能够更高效). 同时,需要注意的是,如果每次删除数据后,都暂停一会儿再做下一次删除,这样也可以将服务器上原本一次性的压力分散到一个很长的时间段,可以降低对服务器的影响,还可以大大减少删除时锁的持有时间 # 分解关联查询 很多高性能的应用都会对关联查询进行分解.简单来说,可以对每一个表进行一次单表查询,然后将结果在应用程序中进行关联 ![](https://box.kancloud.cn/1b8beb116fd4c72afabff26352af4602_545x199.png) 有如下优势 * 让缓存的效率更高.许多应用程序可以方便地缓存单表查询对应的结果对象.例如上面的查中的tag已经被缓存了,那么应用就可以跳过第一个查询.再例如,应用中已经缓存了ID为123,567,9098的内容,那么第三个查询中的IN()中就可以少几个ID,另外,对mysql的查询缓存来说,如果关联的某个表发生了变化,那么就无法使用查询缓存了,而拆分后,如果某个表很少改变,那么基于该表的查询就可以重复利用查询缓存的结果了 * 将查询分解后,执行单个查询可以减少锁的竞争 * 在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展 * 查询本身效率也可能会有所提升,这个例子中,使用IN()代替关联查询,可以让Mysql按照ID顺序进行查询,这可能比随机的关联要更高效,我们后续将详细介绍这点 * 可以减少冗余记录的查询.在应用层做关联查询,意味着对于某条记录应用只需要查询一次,而在数据库中做到关联,则可能重复的访问同一部分数据,从这点看,这样的重构还可能会减少网络和内存的消耗 * 更进一步,这样做相当于在应用中实现了哈希关联,而不是使用Mysql的嵌套循环关联.某些场景哈希关联的效率要高很多 当应用能够方便的缓存单个查询的结果的时候,当可以将数据分布带不同mysql服务器上的时候,当能够使用IN()的方式代替关联查询的时候,当查询中使用同一个表的时候