2012-04-20 103 views
0

我有一個查詢,其中有一些連接。我在這個查詢中加入的每個表都有一個外鍵。當我運行它時,執行時間非常緩慢,大約23秒。 主表有大約50,000行。MySql查詢發送數據緩慢

SELECT o.id, o.title, o.link, o.position_id, o.status, o.publish_date, o.archived_on, vos.name AS site_name, vorib.image AS ribbon, vop.picture, 
      GROUP_CONCAT(DISTINCT CAST(voci.name AS CHAR)) AS cities, 
      GROUP_CONCAT(DISTINCT CAST(vors.name AS CHAR)) AS regions, 
      GROUP_CONCAT(DISTINCT CAST(voi.icon_id AS CHAR)) AS icons, 
       GROUP_CONCAT(DISTINCT CAST(voc.city_id AS CHAR)) AS cities_id, 
      GROUP_CONCAT(DISTINCT CAST(vor.region_id AS CHAR)) AS regions_id, 
      GROUP_CONCAT(DISTINCT CAST(vose.section_id AS CHAR)) AS sections, 
      GROUP_CONCAT(DISTINCT CAST(vocat2.category_id AS CHAR)) AS categories, 
      GROUP_CONCAT(DISTINCT CAST(vocategories.name AS CHAR)) AS categories_names,   
      (SELECT SUM(vocount.clicks) FROM vo_offers_counter AS vocount WHERE vocount.offer_id = vo.id) AS hits 
     FROM vo_offers AS o 
       LEFT JOIN offers_pictures AS vop ON o.id = vop.offer_id AND vop.number = 1 
       LEFT JOIN offer_sites AS vos ON o.site_id = vos.id 
       LEFT JOIN offers_city AS voc ON o.id = voc.offer_id 
       LEFT JOIN offers_category AS vocat ON o.id = vocat.offer_id 
       LEFT JOIN offers_category AS vocat2 ON o.id = vocat2.offer_id 
       LEFT JOIN offer_categories AS vocategories ON vocat2.category_id = vocategories.id 
       LEFT JOIN offers_city AS voc2 ON o.id = voc2.offer_id 
       LEFT JOIN offer_cities AS voci ON voc2.city_id = voci.id 
       LEFT JOIN offers_region AS vor ON o.id = vor.offer_id 
       LEFT JOIN offer_regions AS vors ON vor.region_id = vors.id 
       LEFT JOIN offer_ribbons AS vorib ON o.ribbon_id = vorib.id 
       LEFT JOIN offers_section AS vose ON o.id = vose.offer_id 
       LEFT JOIN offers_icons AS voi ON o.id = voi.offer_id 
       WHERE o.id IS NOT NULL AND o.status IN ('published','pending','xml') 
GROUP BY o.id 
ORDER BY CASE WHEN o.position_id IN('', '0') THEN ~0 ELSE 0 END asc, o.position_id asc, o.publish_microtime desc 
LIMIT 100 OFFSET 200 

這裏是一個DESCRIBE查詢:

+----+--------------------+--------------+--------+---------------------------+---------------------------+---------+--------------------------------------+------+----------------------------------------------+ 
    | id | select_type  | table  | type | possible_keys    | key      | key_len | ref         | rows | Extra          | 
    +----+--------------------+--------------+--------+---------------------------+---------------------------+---------+--------------------------------------+------+----------------------------------------------+ 
    | 1 | PRIMARY   | o   | range | PRIMARY,status   | status     | 2  | NULL         | 3432 | Using where; Using temporary; Using filesort | 
    | 1 | PRIMARY   | vop   | ref | offer_id     | offer_id     | 5  | new_vsichkioferti.v.id    | 1 |            | 
    | 1 | PRIMARY   | vos   | eq_ref | PRIMARY     | PRIMARY     | 4  | new_vsichkioferti.v.site_id   | 1 |            | 
    | 1 | PRIMARY   | voc   | ref | offer_id     | offer_id     | 5  | new_vsichkioferti.v.id    | 2 | Using index         | 
    | 1 | PRIMARY   | vocat  | ref | vo_offers_category_ibfk_1 | vo_offers_category_ibfk_1 | 5  | new_vsichkioferti.v.id    | 1 | Using index         | 
    | 1 | PRIMARY   | vocat2  | ref | vo_offers_category_ibfk_1 | vo_offers_category_ibfk_1 | 5  | new_vsichkioferti.v.id    | 1 |            | 
    | 1 | PRIMARY   | vocategories | eq_ref | PRIMARY     | PRIMARY     | 4  | new_vsichkioferti.vocat2.category_id | 1 | Using index         | 
    | 1 | PRIMARY   | voc2   | ref | offer_id     | offer_id     | 5  | new_vsichkioferti.v.id    | 2 |            | 
    | 1 | PRIMARY   | voci   | eq_ref | PRIMARY     | PRIMARY     | 4  | new_vsichkioferti.voc2.city_id  | 1 | Using index         | 
    | 1 | PRIMARY   | vor   | ref | offer_id     | offer_id     | 5  | new_vsichkioferti.v.id    | 1 |            | 
    | 1 | PRIMARY   | vors   | eq_ref | PRIMARY     | PRIMARY     | 4  | new_vsichkioferti.vor.region_id  | 1 | Using index         | 
    | 1 | PRIMARY   | vorib  | eq_ref | PRIMARY     | PRIMARY     | 4  | new_vsichkioferti.v.ribbon_id  | 1 |            | 
    | 1 | PRIMARY   | vose   | ref | offer_id     | offer_id     | 5  | new_vsichkioferti.v.id    | 1 | Using index         | 
    | 1 | PRIMARY   | voi   | ref | offer_id     | offer_id     | 5  | new_vsichkioferti.v.id    | 1 | Using index         | 
    | 2 | DEPENDENT SUBQUERY | vocount  | ref | offer_id     | offer_id     | 5  | func         | 1 | Using where         | 
    +----+--------------------+--------------+--------+---------------------------+---------------------------+---------+--------------------------------------+------+----------------------------------------------+ 
    15 rows in set 

有什麼事讓這個跑得更快?

[編輯]

問題是在這個連接:

LEFT JOIN offers_city AS voc2 ON o.id = voc2.offer_id 
LEFT JOIN offer_cities AS voci ON voc2.city_id = voci.id 

主要集中在第一個,表offers_city是221339行,但只能用兩列:offer_id和city_id與索引和兩是一個外鍵

+0

通常,「使用filesort」是一個問題的指標。從'ORDER BY'中刪除'CASE'有幫助嗎?因爲在排序之前需要爲每一行計算該表達式,所以每次查詢運行時都需要進行計算。 – DCoder 2012-04-21 07:52:11

回答

2

我看到那裏的WHERE部分只是通過主表(vo_offers AS o)列進行過濾。如果情況總是如此 - 您可以嘗試使用子選擇加速它。你的查詢是這樣的 - 它確實(可能不是100%肯定)首先連接來自連接表的所有其他記錄,然後執行過濾。

所以,你可以嘗試這樣的:

SELECT o.id, o.title, o.link, o.position_id, o.status, o.publish_date, o.archived_on, vos.name AS site_name, vorib.image AS ribbon, vop.picture, 
      GROUP_CONCAT(DISTINCT CAST(voci.name AS CHAR)) AS cities, 
      GROUP_CONCAT(DISTINCT CAST(vors.name AS CHAR)) AS regions, 
      GROUP_CONCAT(DISTINCT CAST(voi.icon_id AS CHAR)) AS icons, 
       GROUP_CONCAT(DISTINCT CAST(voc.city_id AS CHAR)) AS cities_id, 
      GROUP_CONCAT(DISTINCT CAST(vor.region_id AS CHAR)) AS regions_id, 
      GROUP_CONCAT(DISTINCT CAST(vose.section_id AS CHAR)) AS sections, 
      GROUP_CONCAT(DISTINCT CAST(vocat2.category_id AS CHAR)) AS categories, 
      GROUP_CONCAT(DISTINCT CAST(vocategories.name AS CHAR)) AS categories_names,   
      (SELECT SUM(vocount.clicks) FROM vo_offers_counter AS vocount WHERE vocount.offer_id = vo.id) AS hits 
     FROM (SELECT * FROM vo_offers WHERE id IS NOT NULL AND status IN ('published','pending','xml')) AS o 
       LEFT JOIN offers_pictures AS vop ON o.id = vop.offer_id AND vop.number = 1 
       LEFT JOIN offer_sites AS vos ON o.site_id = vos.id 
       LEFT JOIN offers_city AS voc ON o.id = voc.offer_id 
       LEFT JOIN offers_category AS vocat ON o.id = vocat.offer_id 
       LEFT JOIN offers_category AS vocat2 ON o.id = vocat2.offer_id 
       LEFT JOIN offer_categories AS vocategories ON vocat2.category_id = vocategories.id 
       LEFT JOIN offers_city AS voc2 ON o.id = voc2.offer_id 
       LEFT JOIN offer_cities AS voci ON voc2.city_id = voci.id 
       LEFT JOIN offers_region AS vor ON o.id = vor.offer_id 
       LEFT JOIN offer_regions AS vors ON vor.region_id = vors.id 
       LEFT JOIN offer_ribbons AS vorib ON o.ribbon_id = vorib.id 
       LEFT JOIN offers_section AS vose ON o.id = vose.offer_id 
       LEFT JOIN offers_icons AS voi ON o.id = voi.offer_id 
GROUP BY o.id 
ORDER BY CASE WHEN o.position_id IN('', '0') THEN ~0 ELSE 0 END asc, o.position_id asc, o.publish_microtime desc 
LIMIT 100 OFFSET 200 

因此,在這種情況下,你第一個(子查詢中)找到你真正需要的記錄,然後才加入其他表

不知道是否將有所幫助,但你至少可以試試...

+0

感謝您的回答,但是在性能上絕對沒有任何區別 – 2012-04-20 15:46:05

+0

您是否嘗試過將所有連接取出並試圖逐個放回以查看哪一點變慢?我認爲從主表中選擇應該不會那麼慢...... – Laimoncijus 2012-04-20 15:54:04