MySQL中的SELECT DISTINCT语句需要10分钟

MySQL中的SELECT DISTINCT语句需要10分钟,mysql,performance,Mysql,Performance,我是MySQL的新手,我尝试使用以下语句选择一组不同的行: SELECT DISTINCT sp.atcoCode, sp.name, sp.longitude, sp.latitude FROM `transportdata`.stoppoints as sp INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code INNER JOIN `vehicledata`.gtfstrips as t

我是MySQL的新手,我尝试使用以下语句选择一组不同的行:

SELECT DISTINCT sp.atcoCode, sp.name, sp.longitude, sp.latitude
FROM `transportdata`.stoppoints as sp
INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code
INNER JOIN `vehicledata`.gtfstrips as trip ON st.trip_id = trip.trip_id
INNER JOIN `vehicledata`.gtfsroutes as route ON trip.route_id = route.route_id
INNER JOIN `vehicledata`.gtfsagencys as agency ON route.agency_id = agency.agency_id
WHERE agency.agency_id IN (1,2,3,4);
然而,select语句大约需要10分钟,因此显然有些事情正在进行中

一个重要的因素是表
gtfsstop_times
非常庞大。(约2.5亿张唱片)

索引似乎设置正确;以上所有联接都使用索引列。表的大小大致如下:

gtfsagencys - 4 rows
gtfsroutes - 56,000 rows
gtfstrips - 5,500,000 rows
gtfsstop_times - 250,000,000 rows
`transportdata`.stoppoints - 400,000 rows
服务器有22Gb内存,我已经将InnoDB缓冲池设置为8G,我使用的是MySQL 5.6

有人能想出办法让这跑得更快吗?或者说,真的

stoppoints表位于不同的模式中是否重要

编辑: 解释选择。。。返回以下内容:


有2.5亿条记录,我会将gtfsstop_times表分成一列。然后,可以将每个分片表连接到一个单独的查询中,该查询可以在单独的线程中并行运行,您只需合并结果集。

看起来您正试图根据特定条件查找一组停止点。而且,您正在使用
选择DISTINCT
来避免重复的停止点。是这样吗

看起来atcoCode是stoppoints表的唯一键。是这样吗

如果是,请尝试以下方法:

SELECT sp.name, sp.longitude, sp.latitude, sp.atcoCode
  FROM `transportdata`.stoppoints` AS sp
  JOIN ( 
     SELECT DISTINCT st.fk_atco_code AS atcoCode
       FROM `vehicledata`.gtfsroutes AS route
       JOIN `vehicledata`.gtfstrips AS trip ON trip.route_id = route.route_id
       JOIN `vehicledata`.gtfsstop_times AS st  ON trip.trip_id = st.trip_id
       WHERE route.agency_id BETWEEN 1 AND 4
  ) ids ON sp.atcoCode = ids.atcoCode
这样做有几件事:它消除了一个您似乎不需要的表(代理)。它将(a,b,c)中对机构id的搜索从
更改为范围搜索,这可能有帮助,也可能没有帮助。最后,它将
DISTINCT
处理从必须处理整吨数据的情况重新定位到只需处理ID值的子查询情况

JOIN
internal JOIN
是相同的。我使用
JOIN
使查询更容易阅读。)


这会使你的速度加快一点。但是,不得不说,四分之一千兆行的表是一个大表。

诀窍是减少SQL必须计算的gtfsstop\u次的行数。在这种情况下,SQL首先计算gtfsstop_times
transportdata
的内部联接中的每一行。stoppoints
,对吗?
transportdata
.stoppoints有多少行?然后SQL计算WHERE子句,然后计算DISTINCT。它是如何区分的?通过多次查看每一行来确定是否还有其他类似的行。那要花很长时间,对吗

但是,GROUPBY会快速地将所有匹配的行压缩在一起,而不会对每一行进行求值。我通常使用连接来快速减少查询需要计算的行数,然后查看分组

在这种情况下,您希望将DISTINCT替换为grouping

试试这个

SELECT sp.name, sp.longitude, sp.latitude, sp.atcoCode

FROM `transportdata`.stoppoints as sp
    INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code
    INNER JOIN `vehicledata`.gtfstrips as trip ON st.trip_id = trip.trip_id
    INNER JOIN `vehicledata`.gtfsroutes as route ON trip.route_id = route.route_id
    INNER JOIN `vehicledata`.gtfsagencys as agency ON route.agency_id = agency.agency_id

WHERE agency.agency_id IN (1,2,3,4)

GROUP BY sp.name
    , sp.longitude
    , sp.latitude
    , sp.atcoCode

你的问题还有其他有价值的答案,而我的答案是对它的补充。我假设
sp.atcoCode
st.fk_atco_code
是它们表中的索引列

如果可以验证并确保
WHERE
子句中的代理ID有效,则可以消除联接中的联接
`vehicledata
.gtfsagencys`,因为您没有从表中获取任何记录

SELECT DISTINCT sp.atcoCode, sp.name, sp.longitude, sp.latitude
FROM `transportdata`.stoppoints as sp
INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code
INNER JOIN `vehicledata`.gtfstrips as trip ON st.trip_id = trip.trip_id
INNER JOIN `vehicledata`.gtfsroutes as route ON trip.route_id = route.route_id
WHERE route.agency_id IN (1,2,3,4);

如果省略
独立的
限定符,这将如何执行?当您在查询中使用
EXPLAIN
时会得到什么?解释计划是什么?将它粘贴到pastebin或gistI中我不确定如何测试它,因为如果省略限定符,那么将返回大约2.5亿行。抱歉,如果这看起来像胡说八道,我对测试/调试查询有点陌生。请尝试在(sp.name、sp.longitude、sp.latitude、sp.atcoCode)上添加索引;请参阅手册中的部分原因(分组优化建议通常适用于)。但是,是的,我们也来看看解释。使用的是什么文件系统?使用了哪些突袭?使用什么驱动器?e、 你能在回答中再解释一下你所说的“切分”是什么意思吗?谢谢,他是这么说的,出于好奇,这是怎么回事?合并结果集本身会不会像原始作业那样耗时,因为我们正在寻找不同的项?不会,因为查询在较小的表上运行,它们的结果集也较小。+1用于考虑实际SQL并发现这些优化。我甚至不知道可以使用
JOIN(SELECT…
作为有效语法。这将我的查询时间减少了一半,谢谢。我来看看另一个建议的答案。这确实是对我所拥有的内容的重大优化,谢谢你的伟大答案。顺便说一句,@Carlos P,从你选择的
列列表中保留你不需要的任何内容。您是否在应用程序中实际使用了
名称
atcoCode
值?如果没有,就不要问他们:这个结果集大约是兆行的三分之一,从服务器到客户机洗牌这么多数据需要时间。我最终使用了它们,是的——还有很多列我没有检索到+很好的解释。我的查询从没有响应到断开连接,在1.5秒内返回1000行(低于限制)。干杯汉克斯,我试过了,但它实际上增加了查询时间。我尝试了一个小得多的查询(
其中agency.agency_id=1
),通常需要4-5秒,大约需要8秒
sp.name
sp.longitude
sp.latitude
没有索引,这可能是原因吗?我不确定我是否理解按这四列进行分组的逻辑;这是必要的吗?如果必要,我是否应该为它们编制索引?我担心为它们编制索引的性能影响可能会超过其好处。您认为这种方法比@Ollie Jones answer做得更好,因为他的建议似乎执行得更快。我还可以补充一点,我在问题中犯了一个错误,不同的列是sp.atcoCode-这可以解释异常现象吗?实际上我认为@Ollie Jones有最好的