我参加了我学校的数据库课程.老师给了我们一个简单的练习:考虑以下简单的架构:
Table Book:
Column title (primary key)
Column genre (one of: "romance", "polar", ...)
Table Author:
Column title (foreign key on Book.title)
Column name
Primary key on (title, name)
Run Code Online (Sandbox Code Playgroud)
问题包括以下问题:
写出返回写有浪漫书籍的作者的查询.
我提出了这个答案:
select distinct name
from Author where title in (select title from Book where genre = "romance")
Run Code Online (Sandbox Code Playgroud)
然而,老师说这是错的,正确的答案是:
select distinct name
from Book, Author
where Book.title = Author.title
and genre = "romance"
Run Code Online (Sandbox Code Playgroud)
当我要求解释时,我得到的是"如果你更加关注课程,你会知道为什么".辉煌.
那么,为什么我的答案不对?这些查询之间究竟有什么区别?什么究竟他们做,在DB引擎的水平?
a_h*_*ame 27
那么,为什么我的答案不对?
你回答是对的.
我猜是老师为什么把它标记为错误,他/她试图在这个问题上练习使用连接.但如果是有意的话,那应该是问题的一部分.
这些查询之间究竟有什么区别
从技术上讲,它们确实不同.具有简单查询优化器的DBMS将以与教师答案中的连接不同的方式检索子选择.
如果具有良好优化器的DBMS实际上可能为两个查询提出相同的执行计划,我不会感到惊讶.
我创建了一些带有50000本书,50000位作者和7种不同类型的测试数据进行测试(较小的数字并没有真正意义,因为优化器倾向于简单地抓住整个表格).该语句将返回7144行.
执行计划几乎与"join"方法中的一些小变化相同.
以下是子选择版本
的计划:http ://explain.depesz.com/s/eov
以下是加入版本的计划:http://explain.depesz.com/s/aTI
令人惊讶的是,加入版本的成本值略高.
两个计划都是100%完全相同:
-------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6815 | 399K| | 273 (2)| 00:00:04 | | 1 | HASH UNIQUE | | 6815 | 399K| 464K| 273 (2)| 00:00:04 | |* 2 | HASH JOIN | | 6815 | 399K| | 172 (2)| 00:00:03 | |* 3 | TABLE ACCESS FULL| BOOK | 6815 | 166K| | 69 (2)| 00:00:01 | | 4 | TABLE ACCESS FULL| AUTHOR | 50000 | 1708K| | 103 (1)| 00:00:02 | --------------------------------------------------------------------------------------
查看使用时的统计数据autotrace也没有任何区别.我没有打算真正创建一个跟踪文件来分析它,因为我不希望看到那里的差异.
如果book.genre添加了索引,事情就不会真正改变.Oracle坚持全表扫描(即使有100000行).可能是因为表格不是很宽,而且很多行都适合单页.
PostgreSQL确实使用了两个语句的索引,但计划之间仍然没有真正的区别.
Qua*_*noi 15
两个查询都有效并返回相同的内容.
您的教师使用相当过时(但仍然有效)的连接语法,并且您正在使用在某些数据库中效率较低的构造(MySQL例如).
如果我是你的老师,我会把查询写成:
SELECT DISTINCT name
FROM books b
JOIN authors a
ON a.title = b.title
WHERE b.genre = 'romance'
Run Code Online (Sandbox Code Playgroud)
但如果课程不是针对MySQL优化的,那么仍然接受您和您老师的查询.
当他/她说关注时,难道不是老师的意思吗?
更新:
在数据库引擎级别,两个查询都将被优化为使用相同的计划,除非数据库引擎是MySQL.
在MySQL,您的查询将被强制Authors用作前导表,而对于教师的查询,优化器可以根据表统计信息选择要进行前导的表.