Mysql 使用ORDERBY子句优化联接结果

Mysql 使用ORDERBY子句优化联接结果,mysql,query-optimization,Mysql,Query Optimization,考虑以下架构在上可用 在执行简单联接查询时,无需任何顺序: SELECT ad.id, ad.name, category.name, city.name FROM ad INNER JOIN category ON category.id = ad.category_id INNER JOIN city ON city.id = ad.city_id 结果是相当有效的: 但是,只要我添加ORDERBY子句,就会涉及临时表和文件排序: SELECT ad.id, ad.name, catego

考虑以下架构在上可用

在执行简单联接查询时,无需任何顺序:

SELECT ad.id, ad.name, category.name, city.name FROM ad
INNER JOIN category ON category.id = ad.category_id
INNER JOIN city ON city.id = ad.city_id
结果是相当有效的:

但是,只要我添加ORDERBY子句,就会涉及临时表和文件排序:

SELECT ad.id, ad.name, category.name, city.name FROM ad
INNER JOIN category ON category.id = ad.category_id
INNER JOIN city ON city.id = ad.city_id
ORDER BY ad.id

如何优化此类查询?

您可能需要使用STRAIGTH_连接

SELECT STRAIGHT_JOIN ad.id, ad.name, category.name, city.name FROM ad
INNER JOIN category ON category.id = ad.category_id
INNER JOIN city ON city.id = ad.city_id
ORDER BY ad.id

MySQL优化器已选择以错误的顺序访问表。城市、广告、类别最佳访问顺序为广告、类别、城市。STRAIGTH_联接将强制该访问表顺序。

。由于行太少,EXPLAIN无法证明查询计划不好。有一千个广告和几十个城市和类别,优化器可能会选择广告作为第一个要处理的表

此外,优化器不知道您的表是否是多个类别和城市的1个ad。或者很多:很多

你抱怨是因为你知道每个广告只在一个类别和一个城市

BNL和使用连接缓冲区是执行查询的非常有效的方法——它们加载所有内容,然后在RAM中以有效的方式对其进行操作


此外,使用临时文件和使用文件排序也没有听起来那么糟糕。这通常是在RAM中通过有效的内存qsort完成的。

我自己设法找到了一个解决方案。首先,需要从主表中高效地计算所需的ID,并对其进行过滤和排序,然后简单地再次根据内部查询中的键连接结果:

SELECT ad.id, ad.name, category.name, city.name FROM
    (
        SELECT id FROM ad WHERE price <= 3000 ORDER BY id DESC
    ) AS v
JOIN ad ON v.id = ad.id
JOIN category ON category.id = ad.category_id
JOIN city ON city.id = ad.city_id

当然,我的案子涉及到更多的专栏。这种查询在主表中有60k条记录,只要我按索引列排序,执行速度就从0.16s提高到0.004s。

如果需要排序,则需要一个临时表来生成要排序的值,然后对结果值进行排序。。。问题在哪里?????谢谢你的帮助。三分之一还不错。STRAIGHT_JOIN今天工作得很好;明天它可能会强制执行一个不太有利的订单。我有一个包含数千个广告和查询的生产表,它确实产生了相同的结果。我已经设法优化了此查询,并打算将我的解决方案作为明天的答案发布。@mike,请分享您的解决方案,以便每个人都能从中学习:
SELECT ad.id, ad.name, category.name, city.name FROM
    (
        SELECT id FROM ad WHERE price <= 3000 ORDER BY id DESC
    ) AS v
JOIN ad ON v.id = ad.id
JOIN category ON category.id = ad.category_id
JOIN city ON city.id = ad.city_id