2012-12-17 24 views
5

我有这个sql查询在MySQL 5.1非规范化表上运行。它按照我想要的方式工作,但速度可能很慢。我在日期栏中添加了一个索引,但它仍然需要更快。有关如何更快获得此建议的任何建议? (也许有参加呢?)使用算术运算优化MySQL嵌套选择

SELECT DISTINCT(bucket) AS b, 
     (possible_free_slots - 
      (SELECT COUNT(availability) 
      FROM ip_bucket_list 
      WHERE bucket = b 
      AND availability = 'used' 
      AND tday = 'evening' 
      AND day LIKE '2012-12-14%' 
      AND network = '10_83_mh1_bucket')) AS free_slots 
FROM ip_bucket_list 
ORDER BY free_slots DESC; 

各个查询速度快:

SELECT DISTINCT(bucket) FROM ip_bucket_list; 
1024 rows in set (0.05 sec) 

SELECT COUNT(availability) from ip_bucket_list WHERE bucket = 0 AND availability = 'used' AND tday = 'evening' AND day LIKE '2012-12-14%' AND network = '10_83_mh1_bucket'; 
1 row in set (0.00 sec) 

表:

mysql> describe ip_bucket_list; 
+---------------------+--------------+------+-----+-------------------+----------------+ 
| Field    | Type   | Null | Key | Default   | Extra   | 
+---------------------+--------------+------+-----+-------------------+----------------+ 
| id     | int(11)  | NO | PRI | NULL    | auto_increment | 
| ip     | varchar(50) | YES |  | NULL    |    | 
| bucket    | int(11)  | NO | MUL | NULL    |    | 
| availability  | varchar(20) | YES |  | NULL    |    | 
| network    | varchar(100) | NO | MUL | NULL    |    | 
| possible_free_slots | int(11)  | NO |  | NULL    |    | 
| tday    | varchar(20) | YES |  | NULL    |    | 
| day     | timestamp | NO | MUL | CURRENT_TIMESTAMP |    | 
+---------------------+--------------+------+-----+-------------------+----------------+ 

和DESC:

DESC SELECT DISTINCT(bucket) as b,(possible_free_slots - (SELECT COUNT(availability) from ip_bucket_list WHERE bucket = b AND availability = 'used' AND tday = 'evening' AND day LIKE '2012-12-14%' AND network = '10_83_mh1_bucket')) as free_slots FROM ip_bucket_list ORDER BY free_slots DESC; 
+----+--------------------+----------------+------+-----------------------------------------+--------+---------+------+--------+---------------------------------+ 
| id | select_type  | table   | type | possible_keys       | key | key_len | ref | rows | Extra       | 
+----+--------------------+----------------+------+-----------------------------------------+--------+---------+------+--------+---------------------------------+ 
| 1 | PRIMARY   | ip_bucket_list | ALL | NULL         | NULL | NULL | NULL | 328354 | Using temporary; Using filesort | 
| 2 | DEPENDENT SUBQUERY | ip_bucket_list | ref | bucket,network,ip_bucket_list_day_index | bucket | 4  | func | 161 | Using where      | 
+----+--------------------+----------------+------+-----------------------------------------+--------+---------+------+--------+---------------------------------+ 
+0

你可以张贴一些示例行和预期的输出?这可能有帮助。 –

回答

3

我会从移动相关子查询条款列入FROM条款,使用连接:

的每一行(即使 distinct之前运行)
SELECT distinct bucket as b, 
     (possible_free_slots - a.avail) as free_slots 
FROM ip_bucket_list ipbl left outer join 
    (SELECT bucket COUNT(availability) as avail 
     from ip_bucket_list 
     WHERE availability = 'used' AND tday = 'evening' AND 
      day LIKE '2012-12-14%' AND network = '10_83_mh1_bucket' 
    ) on a 
    on ipbl.bucket = avail.bucket 
ORDER BY free_slots DESC; 

SELECT子句中的版本可能正在重新运行。通过将其放入from子句中,ip_bucket_list表将只被扫描一次。另外,如果您希望每个存储桶只显示一次,那么我建议您使用group by而不是distinct。它会澄清查询的目的。您可以完全消除第二参考表,喜欢的东西:

SELECT bucket as b, 
     max(possible_free_slots - 
      (case when availability = 'used' AND tday = 'evening' AND 
         day LIKE '2012-12-14%' AND network = '10_83_mh1_bucket' 
       then 1 else 0 
      end) 
      ) as free_slots 
FROM ip_bucket_list 
group by bucket 
ORDER BY free_slots DESC; 

为了加快您的查询的版本,你需要bucket索引,因为这是用于相关子查询。

+0

感谢您的回复。唯一的是我需要过滤我的第二个SELECT只有当前存储桶的结果。 – Andrew

+0

我最终只是用GROUP BY子句替换了DISTINCT,并且提高了查询的速度。 – Andrew

0

尝试子查询移动到主查询 - 就像这样:

SELECT b.bucket AS b, 
     b.possible_free_slots - COUNT(l.availability) AS free_slots 
FROM ip_bucket_list b 
LEFT JOIN ip_bucket_list l 
     ON l.bucket = b.bucket 
     AND l.availability = 'used' 
     AND l.tday = 'evening' 
     AND l.day LIKE '2012-12-14%' 
     AND l.network = '10_83_mh1_bucket' 
GROUP BY b.bucket, b.possible_free_slots 
ORDER BY 2 DESC