如何在单个查询中使用索引进行多表连接?
Posted
技术标签:
【中文标题】如何在单个查询中使用索引进行多表连接?【英文标题】:How to use indexing for multiple table join in a single query? 【发布时间】:2019-05-04 08:56:54 【问题描述】:具有多个表连接的查询花费了太多时间。如何为下面的查询做索引:
查询:
select ri.id, LOWER(REPLACE(ri.name,' ','-')) as urlName,ri.name,
ri.logo,
group_concat(distinct rc.cuisine order by rc.cuisine asc SEPARATOR ',
'
) as 'cuisine_string', rc.cuisine, rai.rating, rai.min_order_amount,
rai.latitude, rai.longitude, rai.delivery_time, rdf.start_dist,
rdf.end_dist, rdf.fee, ri.address_search, rai.delivery_facility,
ri.status as 'restaurant_status', rt.day, rt.status 'opening_status',
rt.opening_time, rt.closing_time,
' - ',rdf.end_dist,
' km',' : ','₹',fee) SEPARATOR '~') as 'delivery_fee_string',
GROUP_CONCAT(distinct CONCAT(rdf.start_dist, ( SELECT MATCH (ri.address_search) AGAINST ('Kahilipara,
Guwahati, Assam, India') as relevance
from restaurant_info ri
where ri.id = rai.restaurant_id
and ri.id = rt.restaurant_id
and ri.id = rdf.restaurant_id
and ri.id = rc.restaurant_id) as ord , ( 3959 * acos ( cos ( radians(26.1428694) ) * cos( radians( rai.latitude ) ) * cos( radians( rai.longitude ) - radians(91.768487) ) + sin ( radians(26.1428694) ) * sin( radians( rai.latitude ) ) ) ) AS distance
from restaurant_info ri
inner join restaurant_additional_info rai ON ri.id = rai.restaurant_id
inner join restaurant_timing rt ON ri.id = rt.restaurant_id
inner join restaurant_delivery_fee rdf ON ri.id = rdf.restaurant_id
inner join restaurant_cuisine rc ON ri.id = rc.restaurant_id
where ri.status = 1
and rt.status = 1
and rt.day = lower(DATE_FORMAT(NOW(),'%a'))
and rai.delivery_facility != 1
and rai.min_order_amount <= 100
and rai.rating <= ''
and MATCH (ri.address_search) AGAINST ('Kahilipara, Guwahati,
Assam, India'
)
and rt.opening_time < '12:40:21'
and rt.closing_time > '12:40:21'
group by ri.id
having rdf.start_dist = 0
and distance < 3.10686
order by distance asc
LIMIT 100 OFFSET 0
问题描述 - 此查询需要 8.5 秒才能运行。我的应用程序包含 1-2 个这样的查询。因此在服务器上加载时间接近 1 分钟。
谁能帮我在这个查询上应用索引?
【问题讨论】:
如果您真的需要性能,请查看 mysql 的地理空间支持。 在查询中使用 EXPLAIN ......但我想这是消耗时间的计算。有多少记录? 2000 多个记录在那里,我正在为 3 个表使用连接 @LarsStegelitz @TimBiegeleisen 这个问题不是任何人的重复。我根据表格上输入的地址进行获取,然后将其与我的表格进行匹配。 请尝试重复链接中的一种或多种索引技术。 【参考方案1】:为各种表格设置SHOW CREATE TABLE
会有所帮助。另外,EXPLAIN SELECT ...
。
where ri.status = 1
and rt.status = 1
and rt.day = lower(DATE_FORMAT(NOW(),'%a'))
and rai.delivery_facility != 1
and rai.min_order_amount <= 100
and rai.rating <= ''
and MATCH (ri.address_search) AGAINST ('Kahilipara, Guwahati, Assam, India')
and rt.opening_time < '12:40:21'
and rt.closing_time > '12:40:21'
group by ri.id
having rdf.start_dist = 0
and distance < 3.10686
order by distance asc
LIMIT 100 OFFSET 0
由于WHERE
子句中有FULLTEXT
条件,它可能会首先执行此操作。但是,如果这些区域有数千行,我们需要进一步挖掘。
rai.rating <= ''
看起来很奇怪;你对“
having rdf.start_dist = 0
-- 似乎这属于WHERE
子句,而不是HAVING
。
一个大问题是范围测试分散在多个表中:
rt -- just a certain day of the week
rai -- limited amount, etc
ri -- certain regions
rt -- time range, complicated by using 2 columns
即使这些字段在同一个表中,计算成本仍然很高。
distance < ...
-- 如链接中所述,这可以使用“边界框”进行优化,但由于其他问题,它不会有太大帮助。
JOIN ... GROUP BY id
-- 这可能是一个“爆炸-内爆”场景。发生的事情是JOINs
通过加入 1:many 等来扩展正在查看的“行”数。然后GROUP BY
试图回到每个 id 仅一行。如果不是用于所有过滤,则有一些解决方法。
同时,GROUP BY
可能使用不当。见ONLY_FULL_GROUP_BY
。
order by distance LIMIT ..
-- 在排序和交付最多 100 行之前,查询被强制收集所有行(数千?)。
rt.day = lower(DATE_FORMAT(NOW(),'%a'))
- 使用合适的排序规则,您就不需要LOWER()
。
MATCH (ri.address_search) ..
和 distance < ..
似乎是多余的。
为什么有 5 张桌子,每张桌子都用“餐厅 id”作为关键字? (可能有正当理由,但看起来很可疑。)它们是 1:1 还是 1:many?
【讨论】:
他们是 1:1 的关系。这就是为什么我们在每张桌子上都输入了餐厅 ID。 @里克詹姆斯以上是关于如何在单个查询中使用索引进行多表连接?的主要内容,如果未能解决你的问题,请参考以下文章