我有一个查询,其中有一些连接。我在此查询中加入的每个表都有一个外键。当我运行它时,执行时间非常慢,大约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行但只有两列:offer_id和city_id带索引,两者都是外键
答案 0 :(得分: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
所以在这种情况下,你首先(在子选择中)找到你真正需要的记录,然后才加入所有其他表
不确定它是否会有所帮助,但你至少可以尝试一下......