在优化有问题的查询时,目标应该是找到一个更优的方法获得实际需要的结果--而不一定总要从MySQL获取一模一样的结果集。有时候可以查询转换一种写法让其返回一样的结果,但是性能更好。但也可以通过修改应用代码,用另一种方式完成查询,最终达到一样的目的。这里我们将介绍如何通过这种方式来重构查询,并展示合适需要使用这样的技巧。

  1 用一个复杂的查询还是多个简单的查询。

  设计查询的时候一个需要考虑的重要问题是:是否需要将一个复杂的查询分成多个简单的查询。在传统实现中,总是强调需要数据库层完成尽可能多的工作,这样做的逻辑在于以前我那个是认为网络通信,查询解析和优化是一件代价很高的事情。

  但是这样的想法对于MySQL并不适用,MySQL从设计上连接和断开连接都是很轻量级的,在返回一个小的查询结果方面效率很高效。现代的网络速度比之前的要快很多,无论是带宽还是延迟。在某些版本的MySQL上,即使在一个彤彤服务器上,也能够运行每秒超过10W的查询,即使是一个千兆网卡也能轻松满足每秒超过2000次的查询。索引运行多个小查询限制已经不是很大的问题了。

  MySQL内部每秒能够扫描内存中百万行的数据,相比之下,MySQL响应数据给客户端就要慢得多了。在其他条件都相同的时候,使用尽肯能少的查询当然是最好的。但是有时候,将一个大查询分解为多个小查询是很有必要的。别害怕这样做,好哈的衡量一下只有这是不是会减少工作量。稍微我们将通过本章的一个实例来展示这个技巧的优势。

  2切分查询

  有时候对于一个大查询我们需要分而治之,将大查询切分成小查询,每个查询功能完全一样,值完成一小部分,每次只返回以小部分结果。

  删除旧的数据就是一个很好的例子。定期的清理大量数据时,如果用一个大的语句一次性完成的话,则可能要一次锁住很多的数据,占满整个事务日志,好近系统资源,阻塞很多小的但终于的查询。将一个大的DELETE语句切分成多个较小的查询可以尽可能小的影响MySQL的性能,同时还可以减少MySQL复制的延迟。例如我们需要每个月运行一次下面的查询:

  DELETE FROM message WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH);

那么可以用类似下面的办法来完成同样的工作:

  rows_affected = 0

  do{

  rows_affected = do_query("DELETE FROM message  WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH)) LIMIT 10000"}

}while rows_affected > 0

  一次删除1W行数据一般来说是一个比较高效而且对服务器影响也最小的做法(如果是事务型引擎,很多时候笑屎我能够更高效)。同时需要注意的是,如果每次删除数据后,都暂停一会再做下一次删除,这样也可以将服务器上原本一次性的压力分散到一个很长的时间段中,就可以大大降低对服务器的影响,还可以大大减少删除时的锁的持有时间。

  

  3 分解关联查询

  很多高新能的应用都会对关联查询进行分解。简单的说,可以对每一个表进行一次单表查询,然后将结果在应用程序中进行关联,例如,下面的查询:

  SELECT * FROM tag JOIN tag_post on tag_post.tag_id = tag.tag_id JOIN post ON tag_post.post_id = post.id WHERE tag.tag = 'mysql'

  可以分解成下面的这些查询来代替:

  SELECT * FROM tag where tag = 'mysql';

  SELECT * FROM tag_post WHERE tagid=1234;

  SELECT * FROM post WHERE post_id in (123,234,435,342);

  到底为什么要这么做?乍一看,这样走并没有什么好处,原本一条查询,这里却变成多条查询,返回的结果又是一模一样的的。事实上,用分解关联查询的方式重构查询,有如下的优势:

  1让缓存的效率更高。许多应用程序可以方便的缓冲单表查询对应的结果对象。例如:啥忙查询的tag已经被缓存了,那么应用就已经跳过第一个查询。再例如,应用中已经缓存了id为123,234,345的内容,那么第三个查询的in()中就可以少了几个id,另外对应MySQL的查询缓存来说,如果关联中的某个表发生了变化,那么久无法使用查询缓存了,而拆分后,如果某个表很少改变,那么基于该表的查询就可以重复利用查询缓存结果了。

  2 将查询拆分后,执行党查询可以减少锁的竞争。

  3 在应用层做关联,可以更容易对数据库进行拆分,更容易做到高新能和可扩展。

  4 查询本身下来也可能会有所提升。这个例子中使用in()代替关联查询,可以让MySQL按照id顺序进行查询,这可比随机的关联要更高效。我们后续会详细介绍这一点。

  5 可以减少冗余记录的查询。在应用层做关联,意味着对于某条记录应用只需要查询一次,而在数据库中做关联查询,则可能重复的访问同一部分数据。从这点看,这样的重构可能会减少网络和内存的消耗。

  6更进一步,这样做相当于在应用中实现了hash关联,而不是使用MySQL的嵌套循环关联。某些场景中hash的关联效率要高很多。

  在很多场景下,通过重构查询将关联查询放到应用长袖中将会更加高效,这样的场景有很多,比如:当应用能够方便的缓冲单个查询的结果的时候,可以将数据分布到不同的MySQL服务器上的时候,能够使用in()的方式代替关联查询的时候,单反查询中使用同一个数据表的时候。

MySQL重构查询的方式的更多相关文章

  1. MySQL之查询性能优化(一)

    为什么查询速度会慢 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中“执行”可以认为是整个生命周期中最重要的阶段, ...

  2. MySQL慢查询日志配置方式 slow_query_log

    MySQL慢查询(一) - 开启慢查询 - 鲁玉成 - 博客园 https://www.cnblogs.com/luyucheng/p/6265594.html mysql开启慢查询方法 - lava ...

  3. mysql中查询一个字段属于哪一个数据库中的哪一个表的方式

    mysql中查询一个字段具体是属于哪一个数据库的那一张表:用这条语句就能查询出来,其中 table_schema 是所在库, table_name 是所在表 --mysql中查询某一个字段名属于哪一个 ...

  4. MySql学习—— 查询性能优化 深入理解MySql如何执行查询

    本篇深入了解查询优化和服务器的内部机制,了解MySql如何执行特定查询,从中也可以知道如何更改查询执行计划,当我们深入理解MySql如何真正地执行查询,明白高效和低效的真正含义,在实际应用中就能扬长避 ...

  5. MySQL之查询性能优化(二)

    查询执行的基础 当希望MySQL能够以更高的性能运行查询时,最好的办法就是弄清楚MySQL是如何优化和执行查询的.MySQL执行一个查询的过程,根据图1-1,我们可以看到当向MySQL发送一个请求时, ...

  6. 深入理解MySql子查询IN的执行和优化

    IN为什么慢? 在应用程序中使用子查询后,SQL语句的查询性能变得非常糟糕.例如: SELECT driver_id FROM driver where driver_id in (SELECT dr ...

  7. MySQL慢查询日志总结

    慢查询日志概念 MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志 ...

  8. mysql慢查询日志分析工具 mysqlsla(转)

    mysql数据库的慢查询日志是非常重要的一项调优辅助日志,但是mysql默认记录的日志格式阅读时不够友好,这是由mysql日志记录规则所决定的,捕获一条就记录一条,虽说记录的信息足够详尽,但如果将浏览 ...

  9. Mysql慢查询和慢查询日志分析

     Mysql慢查询和慢查询日志分析   众所周知,大访问量的情况下,可添加节点或改变架构可有效的缓解数据库压力,不过一切的原点,都是从单台mysql开始的.下面总结一些使用过或者研究过的经验,从配置以 ...

随机推荐

  1. 如何将github上的微信客户端类库能够通过composer工具下载

    我将自己开发的微信客户端类库放到了github上面去了. 然后我在我的项目里面添加了一个composer.json文件 内容如下 { "require": { "weix ...

  2. linq 的Distinct 扩展方法.

    List<miniclass> classs = new List<miniclass>(); classs.Add(new miniclass() { token = &qu ...

  3. Android ContentProvider 简介

    当在系统中部署一个又一个Android应用之后,系统里将会包含多个Android应用,有时候就需要在小同的应用之问芡亭数据,比如现在有一个短信接收应用,用户想把接收到的陌生短信的发信人添加到联系人管理 ...

  4. COJ 0332 The Flash

    传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=302 The Flash 难度级别:B: 运行时间限制:1000ms: 运行 ...

  5. php header()跳转

    test1.php <?PHP $g_user = "Jack"; echo $g_user; ?> test3.php <?PHP header('Locati ...

  6. Number of 1 Bits——LeetCode

    Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also know ...

  7. [LeetCode] Word Break II 解题思路

    Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each ...

  8. 学习微信小程序之css16常见布局

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. thead、tbody、tfoot与顺序无关

    今天发现一个问题,thead.tbody.tfoot等标签的内容排版与顺序无关,做了一个小的实验:

  10. linux if 判断字符串是否相等

    在命令行中修改时间: 如果linux系统时间等于2017-09-09,则ok:否则将当前系统时间修改为2017-09-09 var=`date '+%Y-%m-%d'`;if [ "$var ...