SQL优化 1

一个很简单的SQL:

  1. select * from point_site_download_queue where status = 0 order by id asc limit 1;  
select * from point_site_download_queue where status = 0 order by id asc limit 1;

<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script> 平均用时达到10秒,可能是lock的关系,但SQL本身也是可以优化的。因为表已经被重建过了,没有数据,所以用另一个类似的SQL为例。

表 user

表 user

+-------------+--------------+------+-----+-------------------+----------------+
| Field       | Type         | Null | Key | Default           | Extra          |
+-------------+--------------+------+-----+-------------------+----------------+
| id          | int(11)      | NO   | PRI | NULL              | auto_increment |
| name        | varchar(40)  | YES  |     | NULL              |                |
| email       | varchar(255) | YES  |     | NULL              |                |
| address     | varchar(255) | YES  |     | NULL              |                |
| age         | int(11)      | YES  | MUL | NULL              |                |
| regist_time | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-------------+--------------+------+-----+-------------------+----------------+

index

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| user  |          0 | PRIMARY  |            1 | id          | A         |     2260431 |     NULL | NULL   |      | BTREE      |         |
| user  |          1 | usertime |            1 | regist_time | A         |          18 |     NULL | NULL   |      | BTREE      |         |
| user  |          1 | userae   |            1 | age         | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |
| user  |          1 | userae   |            2 | email       | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

表中有200万数据。执行

  1. select * from user where address = 'ttt' order by id asc limit 1;  
select * from user where address = 'ttt' order by id asc limit 1;
<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script> 需要3.2秒,使用了主键id。如果给address加上索引呢?看这一个SQL
  1. select * from user  where regist_time = '2007-03-01 13:50:45' order by id asc limit 1;  
select * from user  where regist_time = '2007-03-01 13:50:45' order by id asc limit 1;
<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script>
+----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key      | key_len | ref   | rows | Extra                       |
+----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------------+
|  1 | SIMPLE      | user  | ref  | usertime      | usertime | 4       | const |    1 | Using where; Using filesort |
+----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------------+
用时0秒,这里用到了regist_time上的索引。但是否有索引就一定好?再看这个
  1. select * from user  where regist_time = '2007-02-25 17:36:22' order by id asc limit 1;  
select * from user  where regist_time = '2007-02-25 17:36:22' order by id asc limit 1;
<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script> 用时4.6秒,但如果不用索引
  1. select * from user ignore key(usertime)  where regist_time = '2007-02-25 17:36:22' order by id asc limit 1;  
select * from user ignore key(usertime)  where regist_time = '2007-02-25 17:36:22' order by id asc limit 1;
<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script>
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
|  1 | SIMPLE      | user  | index | NULL          | PRIMARY | 4       | NULL | 2260431 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
用时0秒。这是因为
  1. select count(*), regist_time from user group by regist_time;  
 select count(*), regist_time from user group by regist_time;
<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script>
+----------+---------------------+
| count(*) | regist_time         |
+----------+---------------------+
|   592318 | 2007-02-25 17:20:21 |
|   592318 | 2007-02-25 17:32:28 |
|   592319 | 2007-02-25 17:36:22 |
|        1 | 2007-03-01 13:50:45 |
|   483097 | 2007-03-01 17:09:17 |
+----------+---------------------+
为2007-02-25 17:36:22的值很多,用索引全部选出来后再按id排序会比较慢。而regist_time为这个值的记录id很靠前,从id检索就可以很快找到。因此SQL的优化需要考虑数据的分布。此例中如果时间是2007-03-01 17:09:17,即多其对应的id又不靠前,那么使用这样的SQL会比较好。
  1. select * from user  where id  = (select min(id) from user regist_time = '2007-03-01 17:09:17');  
select * from user  where id  = (select min(id) from user regist_time = '2007-03-01 17:09:17');
<script src="/twiki/pub/TWiki/DpSyntaxHighlighterPlugin/dp.SyntaxHighlighter/Scripts/shBrushSql.js" type="text/javascript"></script>
+----+-------------+-------+-------+---------------+----------+---------+-------+--------+-------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref   | rows   | Extra       |
+----+-------------+-------+-------+---------------+----------+---------+-------+--------+-------------+
|  1 | PRIMARY     | user  | const | PRIMARY       | PRIMARY  | 4       | const |      1 |             |
|  2 | SUBQUERY    | user  | ref   | usertime      | usertime | 4       |       | 759200 | Using index |
+----+-------------+-------+-------+---------------+----------+---------+-------+--------+-------------+
当然对于本例,如果能添加索引(regist_time,id),则速度是最好的,缺点是索引比较大。

在最前面的SQL中,根据业务情况,status为0的值比较少,而且其id总是最大的几个,所以用索引会比较好。给status加上索引后,用下面两个SQL性能都会提高。

  1. select * from point_site_download_queue where status = 0 order by id asc limit 1;   
  2. select * from point_site_download_queue where id = (select min(id) from user where status = 0);   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值