MySQL中关联表前进行投影是否更高效?慢查询优化咨询
嘿,针对你的问题,答案是大部分情况下,提前做投影(只筛选你需要的列)确实能有效提升这类查询的执行效率,不过得结合你的表结构和查询逻辑来看,下面具体说说:
为什么提前投影有用?
减少数据处理量:如果你的源表(比如
occ_wdm_oms、noeud_dico_traitement)包含大量你查询里用不到的列(比如大文本、BLOB或者其他冗余字段),先通过子查询/CTE把需要的列挑出来再关联,能大幅降低MySQL在关联过程中要加载、传输和处理的数据量。比如你的查询只用到了occ_wdm_oms里的OMS_IDTOPO、OMS_SITEA、OMS_SITEB等少数列,那先做个投影:SELECT OMS_IDTOPO, OMS_SITEA, OMS_SITEB, OMS_IDNOEUDA, OMS_IDNOEUDB FROM occ_wdm_oms再拿这个结果去关联其他表,能节省IO和内存开销,尤其是数据量很大的时候,效果会很明显。
提升索引利用率:如果你的投影列刚好能匹配某个联合索引,MySQL可以直接用索引覆盖扫描(Covering Index Scan),不需要回表查询原始数据。比如如果
occ_wdm_oms有一个包含OMS_IDTOPO, OMS_SITEA, OMS_SITEB, OMS_IDNOEUDA, OMS_IDNOEUDB的联合索引,那做投影时MySQL会直接走这个索引,跳过对表主键数据的访问,速度会快很多。优化
DISTINCT的开销:你的查询里用到了DISTINCT,这一步需要对结果集排序去重。如果提前投影减少了单条数据的大小,排序时的内存占用和计算时间都会降低,间接提升整体速度。
什么时候提前投影没用?
- 如果你的源表本身就只有查询用到的这些列,那提前投影完全没必要——MySQL的查询优化器会自动识别,只加载需要的列,多一层子查询反而会增加额外开销。
- 如果你的关联逻辑依赖于没被投影的列,那这种操作不仅没用,还会导致查询出错或者强制MySQL做额外的表扫描。
针对你的查询的具体建议
你的查询里两次关联了noeud_dico_traitement,可以分别对这两次关联的表做投影,只保留需要的列:
SELECT DISTINCT o.OMS_IDTOPO, e.TYPEQPTL, e.LIBUPR, o.OMS_SITEA, o.OMS_SITEB, siteA.Code_Postal as CPA, siteB.Code_Postal as CPB, siteA.Nom_court as NomA, siteB.Nom_court as NomB, siteA.Commune as ComA, siteB.Commune as ComB, siteA.Lat_GPS as latA, siteA.Long_GPS as longA, siteB.Lat_GPS as latB, siteB.Long_GPS as longB FROM ( -- 主表先投影,只取需要的列 SELECT OMS_IDTOPO, OMS_SITEA, OMS_SITEB, OMS_IDNOEUDA, OMS_IDNOEUDB FROM occ_wdm_oms ) as o LEFT JOIN ( -- 关联表A投影,只取需要的列 SELECT Code_DICO, Code_Postal, Nom_court, Commune, Lat_GPS, Long_GPS FROM noeud_dico_traitement ) as siteA ON o.OMS_IDNOEUDA = siteA.Code_DICO LEFT JOIN ( -- 关联表B投影,只取需要的列 SELECT Code_DICO, Code_Postal, Nom_court, Commune, Lat_GPS, Long_GPS FROM noeud_dico_traitement ) as siteB ON o.OMS_IDNOEUDB = siteB.Code_DICO -- 补充你原查询中提到的e表关联,记得也给e表做类似投影处理
另外,别忘了检查关联列的索引情况:occ_wdm_oms.OMS_IDNOEUDA、occ_wdm_oms.OMS_IDNOEUDB和noeud_dico_traitement.Code_DICO是否建立了索引?如果没有,这才是导致查询慢的核心原因,先加索引比投影的效果更显著。
内容的提问来源于stack exchange,提问作者tsu

