如何在单个查询中的多个表联接中使用索引?

时间:2019-05-04 08:56:55

标签: php mysql query-performance

具有多个表联接的查询花费太多时间。如何为以下查询建立索引:

查询:

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分钟。

有人可以帮助我对此查询应用索引编制吗?

1 个答案:

答案 0 :(得分:0)

为各个表使用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

由于FULLTEXT子句中有一个WHERE条件,因此它可能会首先这样做。但是,如果这些区域中有成千上万的行,我们需要进一步挖掘。

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:很多?