如何加快对 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 行)的主要内容,如果未能解决你的问题,请参考以下文章