语句如下
SELECT pni.parent_name, ni.name, dt.data_time, dt.value_a, dt.value_b FROM data_table dt LEFT JOIN rel_table rt ON dt.data_id = rt.rel_id LEFT JOIN name_info ni ON rt.rel_b_id = ni.rel_b_id LEFT JOIN parent_name_info pni ON ni.parent_id = pni.parent_id WHERE dt.data_time > ${dayTime} AND dt.data_time <= date_add(${dayTime},INTERVAL 1 DAY) AND pni.parent_id IN ( SELECT parent_id FROM parent_list)
mysql 的版本是 5.7 ,现在的情况是这个语句查询不出来。 数据表日期范围内的数据大概是不到 1W 条,rel 表中的数据不到 200 条。 ni 和 pni 这两个表中的数据可能有几十万条。
![]() | 1 encro 2024-04-10 10:46:32 +08:00 explain 结果出来看下再说 |
![]() | 2 encro 2024-04-10 10:47:37 +08:00 dt 的 parnet_id 加 data_time 建立组合索引。 |
3 Cruzz 2024-04-10 10:50:00 +08:00 左关联会关联所有数据,形成大表再筛选,先筛选再关联减少连接数。你这数据量还没到扒着看的程度 |
![]() | 4 me1onsoda 2024-04-10 11:04:02 +08:00 以我浅薄的知识,恐怕没有什么好办法。我可能会把 pni.parent_id IN 这个 clause 放到表连接中,提高过滤率 |
![]() | 5 kwater 2024-04-10 11:08:18 +08:00 IN ( SELECT parent_id FROM parent_list) 这个必须改 join ,否则你可能在某些人的偏执下会失去工作 |
![]() | 6 leon1900 2024-04-10 11:09:29 +08:00 parent_list 多少条数据 |
![]() | 7 ukipoi OP @encro 结果是这个。 id select_type `table` partitions `type` possible_keys `key` key_len `ref` `rows` filtered Extra 1 SIMPLE rt ALL rel_id,data_id 187 100 Using where 1 SIMPLE ni ref rel_id rel_id 111 test.rt.rel_id 1 100 1 SIMPLE dt ref data_id,data_time data_id 110 test.rt.data_id 232 3.73 Using where 1 SIMPLE pni ALL 96014 10 Using where; Using join buffer (Block Nested Loop) 1 SIMPLE <subquery2> eq_ref <auto_key> <auto_key> 110 test.pni.parent_id 1 100 2 MATERIALIZED parent_list index parent_id parent_id 110 185 100 Using index |
![]() | 9 qiqw 2024-04-10 11:16:33 +08:00 关注 |
![]() | 10 ukipoi OP @Richared 我试着把条件都写在 join 的表里了,最终结果大概是 A ( 9000 ) B ( 200 ) C ( 200 ) D(50) 这 4 个表关联,还是出不来结果 我看这 4 个表做全关联要 180W 数据了,mysql 会这样么。 主要是之前用的都是 oracle ,自己数据库也不太行,oracle 关联好像可以直接出数据。 |
![]() | 11 Felix0504 2024-04-10 11:18:09 +08:00 ![]() @ukipoi #7 你的 rt 和 pni 都是全表扫描,rt 数据量小也就算了,pni 数据量大,全表扫描肯定耗时,parent_id 加索引了吗 |
![]() | 12 elkfnmoyu 2024-04-10 11:19:20 +08:00 3 楼说的对,子查询里 data_time 先筛选 data_table 数据,然后再用子查询关联其他表 |
![]() | 13 leon1900 2024-04-10 11:20:54 +08:00 ![]() pni.parent_id 没索引吗 |
16 Cruzz 2024-04-10 11:29:52 +08:00 @ukipoi 这样的问题,首先考虑减小关联数,然后是否是全量返回,数据量大小多大,最后看你的条件走没走索引,尤其大表。你把条件写里边就是一个一个的简单查询,这个判断走不走索引,该怎么建立索引就简单多了,照着操作就行了。基本都能解决。 |
17 fxjson 2024-04-10 11:54:16 +08:00 ![]() 如果是我的话,首先 data_time 添加索引, 其次 date_add(${dayTime},INTERVAL 1 DAY)去掉使用 date_add 函数, 其次,子查询在应用中单独 sql 查询出结果然后用 in(xxx,xxx), 最后看看 on 字段是否建立了对应的索引 最后根据 explain 看结果进行分析是否有改进,如果上面几步都改了,sql 大概率不会有其他问题了 |
![]() | 18 encro 2024-04-10 17:12:34 +08:00 @ukipoi #7 前有人提到过,就是 pni.parent_id 的问题,rows 96014 就它最大,且没有利用索引。 给 pni.parent_id 建立索引就解决了。 基本所有关联外键都需要建立索引的。 |
![]() | 19 aliveyang 2024-04-10 23:44:37 +08:00 pni.parent_id IN ()既然有这个条件了, LEFT JOIN 是不是没必要了 |