2012-12-17 5 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 into句句、ジョインを使用:SELECT句のバージョンは、おそらく(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; 

を。 from句に入力すると、ip_bucket_listテーブルが1回だけスキャンされます。

また、各バケットが1回だけ表示されることを期待している場合は、distinctではなくgroup byを使用することをおすすめします。これは、クエリの目的を明確にします。あなたが好きなもので、完全にテーブルへの第二の基準を解消できる場合があります。これは相関サブクエリに使用されるため

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

ご返信ありがとうございます。唯一のことは、現在のバケットの結果だけで2番目のSELECTをフィルタリングする必要があったことです。 – Andrew

+0

私はDISTINCTをGROUP BY句に置き換えてしまいました。 – 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