如何加快对 3 个表的 MySQL 查询(总共大约 60M 行)

Posted

技术标签:

【中文标题】如何加快对 3 个表的 MySQL 查询(总共大约 60M 行)【英文标题】:How to speedup MySQL query on 3 tables ( around 60M rows together ) 【发布时间】:2015-11-25 16:37:14 【问题描述】:

现在我有一个应用程序,我从 3 个 mysql 表中选择了 4 个,其中下一个总是基于我从以前获得的数据。

选择:

// Search by single input from user, the VIN

SELECT * FROM axnmrs_cases WHERE vin = :vin ORDER BY date_created DESC

好的,现在我有多个关于这个 VIN 的所有案例的数据 现在我针对每个案例进行这种搜索:

// case_id and country are from axnmrs_cases table
SELECT * FROM axnmrs_calculations WHERE case_id = :case AND country = :country ORDER BY calculation_id DESC LIMIT 1

在这一切之后,我尝试在第三张表中找到一些详细信息:

// calculation_id is from axnmrs_calculations and case_id is same as previous
SELECT text FROM axnmrs_positions WHERE calculation_id = :calculationid AND case_id = :case_id AND repairmethod LIKE 'L%' LIMIT 60
// and this:
SELECT text FROM axnmrs_positions WHERE calculation_id = :calculationid AND case_id = :case_id AND repairmethod = 'E' AND guidenumber != 'N/A

问题是如何编写单个语句来快速完成所有这些。 我已经尝试编写为我执行此操作的查询,但是我什至没有完成它,因为下面的代码已经花费了大约 5 分钟:

SELECT c.vin, c.case_id, c.axrmrs_id, c.insurer_memberid, c.country, c.date_created, c.totalloss, c.lastcalc_manufacturer_code, c.audavin_triggered, c.accident_date, c.registration_date, c.manufacturing_year, cl.totalcosts, cl.laborhours, cl.laborcosts, 
  GROUP_CONCAT(DISTINCT IF(po.repairmethod LIKE 'L%',po.text,NULL) ORDER BY 1) AS textL,
  GROUP_CONCAT(DISTINCT IF(po.repairmethod LIKE 'E%',po.text,NULL) ORDER BY 1) AS textE
FROM axnmrs_cases AS c 
  LEFT JOIN axnmrs_calculations as cl on c.case_id = cl.case_id 
  LEFT JOIN axnmrs_positions as po on c.case_id = po.case_id 
WHERE c.vin='U5YFF24128L064909' 
  GROUP BY c.vin, c.case_id, c.axrmrs_id

这个原因可能是表格的行数

#1 cases - ~3 486 114
#2 calculations - ~2 061 554
#3 positions - ~55 078 708

伙计们,我需要这个来为前端创建 API,但是我不想多次再次选择表格。

有什么方法可以加快我的查询速度吗? 现在我在所有“WHERE”选择列上都有索引。

感谢您的建议

编辑: 我正在添加索引列表:

cases:
     -id
     -vin
calculations:
     -case_id
positions:
     -calculation_id

【问题讨论】:

表上的索引是什么?执行计划也会有所帮助。 嘿@EvaldasBuinauskas 我刚刚在我的问题中添加了索引,对不起,我觉得很笨,但不确定你对“执行计划”的意思 @Andurit:以EXPLAIN为前缀执行查询,您将获得查询计划。如果可能的话,我建议将 MySQL 换成 PostgreSQL,因为它在优化查询方面更加智能。 我不确定您的每个表中有多少行。所以这是基于每个表都有几乎相同的大小。而且我认为左连接不是您想要的(也许内连接就足够了)由于您使用左连接并且条件基于case_id,因此它将在位置和案例表中进行全表扫描,并在计算中进行索引扫描桌子。全表扫描会占用大量资源。如果你想提高搜索速度,你需要为职位和案例添加索引。 嗨@RogerDwan,它在最后,所以很容易错过,我的问题是每个表的行数:) 但是它是:#1 案例 - ~3 486 114 #2 计算 - ~2 061 554 #3 位置 - ~55 078 708 【参考方案1】:

请提供SHOW CREATE TABLE

WHERE vin = :vin ORDER BY date_created DESC 需要这个复合索引:INDEX(vin, date_created)

WHERE case_id = :case AND country = :country ORDER BY calculation_id DESC 需要INDEX(case_id, country, calculation_id)INDEX(country, case_id, calculation_id)

INDEX(calculation_id, case_id, repairmethod)INDEX(case_id, calculation_id, repairmethod)

FROM axnmrs_cases AS c LEFT JOIN axnmrs_calculations as cl on c.case_id = cl.case_id LEFT JOIN axnmrs_positions as po on c.case_id = po.case_id WHERE c.vin='U5YFF24128L064909' -- c 需要:INDEX(vin),而 cl 和 pl 需要:INDEX(case_id)。不要说LEFT,除非你的意思是“右”表是可选的。

请注意,第一个查询中的INDEX(vin, date_created) 足以满足此处的 vin 索引。

见我的Index Cookbook

【讨论】:

以上是关于如何加快对 3 个表的 MySQL 查询(总共大约 60M 行)的主要内容,如果未能解决你的问题,请参考以下文章

mysql查询优化

如何结合 3 个表的结果来计算 MySql 中的平均分?

跨 2 个表的 Mysql SQL 查询 - 不知道如何正确执行

带有一个动态列的3个表的mysql查询(i18n)

排序通过3个表MYSQL

MYSQL:用union查询2个表很慢,如何改进?