2012-12-17 43 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