回答

收藏

仅在没有子行的情况下选择父行

技术问答 技术问答 299 人阅读 | 0 人回复 | 2023-09-14

我有一个MySQL数据库,其中表A与表B具有一对多关系,我想选择表B中表A中没有子项的所有行。
2 h& l: Q$ ?: MSELECT id FROM A WHERE NOT EXISTS (SELECT * FROM B WHERE B.id=A.id)# Y: q; G2 [: ^7 |
, S, s6 ]! ^" h0 c9 l
SELECT id FROM A LEFT JOIN B ON A.id=B.id WHERE B.id IS NULL
" H  R% }1 k: @/ s4 D: C# t, c. |两者似乎都很慢。是否有更快的查询来实现相同的目的?
8 M6 z1 i+ C: V如果这是相关的,在我的数据库中,表A大约有500,000行,表B大约有3到4百万行。$ E& z4 @# _/ ~! M0 W
编辑: 对于我的数据库中的实际表,解释给我:6 `2 f% a3 ?; `7 x& k" Y1 B
+----+--------------------+------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
( D& V% y4 O( ~9 a9 {& i| id | select_type        | table            | type  | possible_keys | key                       | key_len | ref  | rows    | Extra                    |6 g* C* B2 \# Y: f
+----+--------------------+------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+2 }0 t' t  G) s
|  1 | PRIMARY            | frontend_form471 | index | NULL          | frontend_form471_61a633e8 | 32      | NULL |  671927 | Using where; Using index |
" {7 Y( I+ ~' q|  2 | DEPENDENT SUBQUERY | SchoolData       | index | PRIMARY       | PRIMARY                   | 49      | NULL | 3121110 | Using where; Using index |
# P6 T  M" f0 |" Q+----+--------------------+------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
2 @# L% ^0 `0 D+ W7 q2 W为了
; g! k& h" n4 ]: `5 P3 d( J1 Rselect number from frontend_form471 where not exists (select * from SchoolData where SchoolData.`f471 Application Number`=frontend_form471.number)+ k! w7 I  |0 _4 ?
: Q- W% F$ R7 U3 C1 q" ?/ e, O4 `7 N, ?
+----+-------------+------------------+-------+---------------+---------------------------+---------+------+---------+------------------------------------------------+- X- x. r& u4 V& ?/ V1 x) G
| id | select_type | table            | type  | possible_keys | key                       | key_len | ref  | rows    | Extra                                          |
  G' @& l( E. I* q% L$ X. Y+----+-------------+------------------+-------+---------------+---------------------------+---------+------+---------+------------------------------------------------+5 H" [: p; A; m2 r5 `2 V: L3 K6 c3 I
|  1 | SIMPLE      | frontend_form471 | index | NULL          | frontend_form471_61a633e8 | 32      | NULL |  671927 | Using index; Using temporary                   |
7 L& h. \2 \% e|  1 | SIMPLE      | SchoolData       | index | PRIMARY       | PRIMARY                   | 49      | NULL | 3121110 | Using where; Using index; Not exists; Distinct |
! o  H0 s$ K* K) h; o+----+-------------+------------------+-------+---------------+---------------------------+---------+------+---------+------------------------------------------------+
- h3 L! B" E7 r' K+ X为了
7 o) n; x9 V) _, Fselect distinct number from frontend_form471 left join SchoolData on frontend_form471.number=SchoolData.`f471 Application Number` where SchoolData.`f471 Application Number` is NULL
$ ]3 u0 O" [( F5 X+ E! c% g% J在我的情况下,frontend_form471是表A,SchoolData是表B
2 @( `- Z+ F  L+ I! k  G( EEdit2: 在我数据库的表B(SchoolData)中,id是两部分主键的第一部分,因此已对其进行了索引,并且B中仍然存在多个具有相同id的条目。- h. ~8 L' y9 u& B5 D
                8 C- |* u4 k: J) \* g5 a
解决方案:
0 w0 z$ c/ ^0 K, Z+ n                7 J$ b+ M" W0 ^4 s1 |
% s: V5 [0 `) Y+ p
; p& _0 |: ]- n; q
                SELECT id FROM A LEFT OUTER JOIN B ON A.id=B.id WHERE B.id IS NULL
9 k( m8 f* `9 |* R你可以这样做。外部联接应该带来一点性能,但不是很多。
2 n3 l5 F5 ?( z& @$ Z新的数据库系统可能仍会优化您的查询,因此不会有任何差异。7 x0 ^, Y9 B2 X9 O/ C6 |
正确的方法是缓存!如果可能,请尝试查询缓存和应用程序级缓存。5 I: T- d5 ~' s9 l- C$ z
当然,您需要适当的索引。1 U+ z; u, x5 M$ p, J9 e: V& `
正确地说,我的意思是在两个表上最好是一个哈希索引,因为与具有对数的任何树相比,它具有静态查找时间
& ?( \2 V6 P4 B2 G2 s尝试在查询前放置一个解释,以了解到底是什么使速度变慢了。/ B, `0 I6 G2 ]- v3 ?
如果您确实需要此方法来加快速度,则可以重新构建数据结构。
. l2 k7 L( d" n6 M. [您可以创建一个触发器来标记表A中的标志,表be中是否存在相应的条目。当然,这种id数据冗余,但有时值得。只是将其视为缓存。
" i) @( H/ z  {' C6 M最后一个想法:您可以尝试SELECT id FROM A WHERE id NOT IN (SELECT id FROM
7 P$ @5 j6 X  h, [$ ?B)这样做可能会更快一些,因为不需要实际的连接,但是它也可能会比较慢,因为在be集合中的查找将是一次完整扫描。我不确定该如何处理,但值得一试。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则