《高性能MySQL》重构查询方式

287次阅读
没有评论

1. 一个复杂查询还是多个简单查询

设计查询的时候一个需要考虑的重要问题是,是否需要将一个复杂的查询分成多个简单的查询。

2. 切分查询

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

删除旧数据就是一个很好的例子。定期的清除大量数据时,如果一个大的语句一次性完成的话则可能一次锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞很多小的但很重要的查询。将一个大的 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(),INTEVAL 3 MONTH) LIMIT 10000”)
} while rows_affected > 0

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

3. 分解关联查询

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

mysql> SELECT * FROM tag
-> JOIN tag_post ON tag_post.tag_id=tag.id
-> JOIN post ON tag_post.post_id=post.id
-> WHERE tag.tag=’mysql’;

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

mysql> SELECT * FROM tag WHERE tag=’mysql’;
mysql> SELECT * FROM tag_post WHERE tag_id=12345;
mysql> SELECT *FROM post WHERE post.id in(123,456,567,9098,8904);

分解关联查询的优势如下:

1)让缓存效率更高。许多应用程序可以方便的缓存单表查询对应的结果对象。例如上面查询中的 tag 已经被缓存了,那么就可以跳过第一个查询。再例如,应用中已经换成了 ID 为 123,567,9098 的内容,那么第三个查询的 IN() 中就可以少几个 ID。另外,对于 MySQL 的查询缓存来说,如果关联中的某个表发生了变化,那么就无法使用查询缓存了,而拆分后,如果某个表很少改变,那么基于该表的查询可以重复鲤鱼查询缓存结果了。
2)将查询分解后,执行单个查询可以减少锁的竞争。
3)在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展。
4)查询本身效率也可能会有所提升。这个例子中,使用 IN() 代替关联查询,可以让 MySQL 阿内 ID 顺序进行查询,咋肯比随机的关联要更高效。
5)可以减少冗余记录的查询。在应用层做关联查询,意味着对于某条记录只需要查询一次,而在数据库中做关联查询,则可能需要重复的访问一部分数据。从这点看,这样的重构还可能减少网络内的内存消耗。
6)更进一步,这样做相当于在应用中实现了哈希关联,而不是使用 MySQL 的嵌套循环关联。某些场景哈希关联的效率要高很多。

正文完
有偿技术支持加微信
post-qrcode
 0
评论(没有评论)
验证码