仅当父行没有子项时才选择父行

mur*_*d99 10 mysql sql

我有一个MySQL数据库,其中表A与表B有一对多的关系,我想选择表B中表A中没有子项的所有行.我试过使用

SELECT id FROM A WHERE NOT EXISTS (SELECT * FROM B WHERE B.id=A.id)
Run Code Online (Sandbox Code Playgroud)

SELECT id FROM A LEFT JOIN B ON A.id=B.id WHERE B.id IS NULL
Run Code Online (Sandbox Code Playgroud)

这两个似乎都很慢.是否有更快的查询来实现同样的事情?

如果这是相关的,在我的数据库表A中有大约500,000行,而表B有大约3到4百万行.

编辑:对于我数据库中的实际表,解释给了我:

+----+--------------------+------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
| id | select_type        | table            | type  | possible_keys | key                       | key_len | ref  | rows    | Extra                    |
+----+--------------------+------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
|  1 | PRIMARY            | frontend_form471 | index | NULL          | frontend_form471_61a633e8 | 32      | NULL |  671927 | Using where; Using index |
|  2 | DEPENDENT SUBQUERY | SchoolData       | index | PRIMARY       | PRIMARY                   | 49      | NULL | 3121110 | Using where; Using index |
+----+--------------------+------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
Run Code Online (Sandbox Code Playgroud)

对于

select number from frontend_form471 where not exists (select * from SchoolData where SchoolData.`f471 Application Number`=frontend_form471.number)
Run Code Online (Sandbox Code Playgroud)

+----+-------------+------------------+-------+---------------+---------------------------+---------+------+---------+------------------------------------------------+
| id | select_type | table            | type  | possible_keys | key                       | key_len | ref  | rows    | Extra                                          |
+----+-------------+------------------+-------+---------------+---------------------------+---------+------+---------+------------------------------------------------+
|  1 | SIMPLE      | frontend_form471 | index | NULL          | frontend_form471_61a633e8 | 32      | NULL |  671927 | Using index; Using temporary                   |
|  1 | SIMPLE      | SchoolData       | index | PRIMARY       | PRIMARY                   | 49      | NULL | 3121110 | Using where; Using index; Not exists; Distinct |
+----+-------------+------------------+-------+---------------+---------------------------+---------+------+---------+------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

对于

select distinct number from frontend_form471 left join SchoolData on frontend_form471.number=SchoolData.`f471 Application Number` where SchoolData.`f471 Application Number` is NULL
Run Code Online (Sandbox Code Playgroud)

在我的情况下,frontend_form471是表A,而SchoolData是表B.

Edit2:在我的数据库中的表B(SchoolData)中,id是两部分主键的第一部分,因此它被编入索引,并且B中仍有多个具有相同id的条目.

The*_*can 9

SELECT id FROM A LEFT OUTER JOIN B ON A.id=B.id WHERE B.id IS NULL
Run Code Online (Sandbox Code Playgroud)

你可以这样做.外连接应该带来一点性能,但不是很多.

无论如何,新的数据库系统可能会优化您的查询,以便不会有任何区别.

这里正确的方法是缓存!如果可能,尝试查询cacher和应用程序级缓存.

当然你需要适当的索引.

并且恰当地意思是在两个表上并且优选地是哈希索引,因为它将具有与具有对数的任何树的比较的静态查找时间

尝试在查询之前添加一个解释,看看真正减慢了什么.

如果你真的需要这么快,你可能会重新制定你的数据结构.

您可以创建一个触发器来标记表A中的标志,表中是否有相应的条目.当然这个id数据冗余,但有时它值得.把它想象成缓存.

最后一个想法:你可以尝试SELECT id FROM A WHERE id NOT IN (SELECT id FROM B)它可能会更快一点,因为不需要实际连接,但它也可能更慢,因为在集合中的查找将是一个完整的扫描.我不确定这将如何处理,但它可能值得一试.

  • 只有MySQL有这个:其他引擎更好用NOT EXISTS http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/ (2认同)