0

いくつかの結合を含むクエリがあります。このクエリで結合したすべてのテーブルには外部キーがあります。実行すると、実行時間は非常に遅く、約 23 秒です。メイン テーブルには約 50,000 行あります。

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 行ありますが、2 つの列しかありません: インデックス付きの offer_id と city_id で、両方が外部キーです

4

1 に答える 1

2

メインテーブル (vo_offers AS o) 列だけでフィルタリングする WHERE 部分があることがわかります。常にそうである場合は、副選択を使用して高速化を試みることができます。あなたのクエリの問題は、最初に結合されたテーブルから他のすべてのレコードを結合してから、フィルタリングを実行することです (おそらく、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  

したがって、この場合、最初に (副選択で) 本当に必要なレコードを見つけてから、他のすべてのテーブルを結合します

役に立つかどうかはわかりませんが、少なくとも試してみることはできます...

于 2012-04-20T15:36:02.827 に答える