2012-12-17 35 views
5

Tôi có truy vấn sql này chạy trên bảng MySQL không chuẩn hóa MySQL 5.1. Nó hoạt động theo cách tôi muốn nó, nhưng nó có thể khá chậm. Tôi đã thêm chỉ mục vào cột ngày nhưng vẫn cần phải nhanh hơn. Bất kỳ đề xuất về cách để có được điều này nhanh hơn? (Có thể với một tham gia để thay thế?)Tối ưu hóa MySQL lồng nhau được chọn với phép tính số học

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; 

Các truy vấn cá nhân là nhanh:

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) 

Bảng:

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 |    | 
+---------------------+--------------+------+-----+-------------------+----------------+ 

và 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

Bạn có thể gửi một số hàng mẫu và kết quả mong muốn? Điều đó có thể hữu ích. –

Trả lời

3

tôi sẽ di chuyển truy vấn con tương ứng từ SELECT khoản vào mệnh đề FROM, sử dụng một tham gia:

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; 

Phiên bản trong mệnh đề SELECT có lẽ được chạy lại cho mỗi hàng (thậm chí trước khi distinct đang chạy). Bằng cách đặt nó trong mệnh đề from, bảng ip_bucket_list sẽ chỉ được quét một lần.

Ngoài ra, nếu bạn dự kiến ​​mỗi nhóm chỉ hiển thị một lần, thì tôi khuyên bạn nên sử dụng group by thay vì distinct. Nó sẽ làm rõ mục đích của truy vấn. Bạn có thể để loại bỏ các tài liệu tham khảo thứ hai để bàn hoàn toàn, với một cái gì đó như:

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; 

Đẩy nhanh tiến độ các phiên bản của các truy vấn, bạn cần một chỉ mục trên bucket, bởi vì đây được sử dụng cho các subquery tương quan.

+0

Cảm ơn bạn đã trả lời. Điều duy nhất là tôi cần phải lọc lựa chọn thứ hai của tôi chỉ với kết quả cho thùng hiện tại. – Andrew

+0

Tôi đã kết thúc chỉ thay thế DISTINCT với mệnh đề GROUP BY và tăng tốc truy vấn. – Andrew

0

Hãy thử di chuyển subquery vào truy vấn chính - như vậy:

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