Slow Query Basics: Optimize Data Access

查询太慢的一个最基本的原因就是:处理的数据太多了。

1. 看看你的应用获取的数据是否大于它需要的数据

2. 看看MySQL Server是否分析了大于它需要的数据

 

常见的错误

1.Fetching more rows than needed

2. Fetching all columns from a multitable join

3. Fetching all columns

4. Fetching the same data repeatedly

 

重建查询的方法

分解查询(任务)

比如清理表数据,如果一次清理得太多,那么很多行会被锁住,挡住其他查询等。所以把DELETE的任务分解成小块来执行能很明显提升性能。

mysql> DELETE FROM messages 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

 

分解联表

如:

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=1234;
mysql> SELECT * FROM post WHERE post.id in (123,456,567,9098,8904);

这样的优点有:

  • 缓存更有效
  • 减少锁表竞争
  • 方便数据库部署在不同的服务器上面
  • 单个的SQL效率更高,如IN()要比联表来得快
  • 减少access的行,因为联表本身是反范式的,会重复查很多数据
  • 类似于hash联表的技术

 

查询执行的基础

1. 客户端向服务端发送SQL语句

2. 服务端先找缓存,如果有直接返回结果,否则进入下一步

3. 服务端编译、预处理和优化SQL

4. 查询执行引擎通过调用存储引擎的API来执行SQL

5. 服务端返回结果

 

The MySQL Client/Server Protocol

Mysql的C/S协议是half duplex的,就是说,服务端可以发送也可以接受信息,但是不能同时发送和接受信息

客户端一次请求只发送一个包,max_allowed_packet 决定了服务端能接受的最大的包,如果你的请求太大了,服务器会报错并不再接受客户端的请求。

相反的,服务端能返回很多包给客户端,客户端必须要接受全部的服务端结果,而不能接受一部分后告诉服务端我不再需要了。这就是为什么SQL里加上LIMIT很重要。

也就是说,客户端不是从服务端“拉”数据,而是服务端把数据“推“过来,这个过程是被动的,不能被客户端停止的。

1 <?php
2 $link = mysql_connect('localhost', 'user', 'p4ssword');
3 $result = mysql_query('SELECT * FROM HUGE_TABLE', $link);
4 while ( $row = mysql_fetch_array($result) ) {
5 // Do something with result
6 }

举个例子,上面的代码看起来好像是你需要数据的时候再去fetch,但事实上,数据在调用mysql_query的时候已经在缓存里了,调用mysql_fetch_array时只是在和缓存对话。

 

Query states

使用SHOW FULL PROCESSLIST

Sleep: 等待客户端的请求

Query: 执行请求或是向客户端推送数据

Locked: 等待服务端给一个锁表的权限

Analyzing and statistics: 检查存储引擎的数据和优化查询

Copying to tmp table [ on disk ]: 将查询结果放入缓存表,UNION, GROUP BY都有可能导致

Sorting result

Sending data

 

The Query Cache

 

The Query Optimization Process

Reordering joins: 联表的顺序会被优化

Converting OUTER JOINs to INNER JOINs