18

我在学校参加数据库课程。老师给了我们一个简单的练习:考虑以下简单的模式:

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)

问题包括以下一个:

编写返回写过言情小说的作者的查询。

我提出了这个答案:

select distinct name 
from Author where title in (select title from Book where genre = "romance")

但是老师说错了,正确答案是:

select distinct name 
from Book, Author 
where Book.title = Author.title 
  and genre = "romance"

当我要求解释时,我得到的只是“如果你对这门课多加注意,你就会知道为什么”。杰出的。

那么,为什么我的答案不正确?这些查询之间到底有什么区别?在数据库引擎级别,他们到底做了什么

4

2 回答 2

27

那么,为什么我的答案不正确?

你的回答正确的。

我猜为什么老师将其标记为错误,他/她试图练习使用该问题的连接。但如果它是有意的,那应该是问题的一部分。

这些查询之间到底有什么区别

从技术上讲,它们确实不同。具有简单查询优化器的 DBMS 将以不同于老师答案的连接方式检索子选择。

如果具有良好优化器的 DBMS 实际上可能为两个查询提供相同的执行计划,我不会感到惊讶。

编辑

我创建了一些包含 50000 本书、50000 位作者和 7 种不同类型的测试数据来测试(较小的数字实际上没有意义,因为优化器往往会简单地抓取整个表格)。该语句将返回 7144 行。

PostgreSQL

执行计划与“join”方法的一些小变化几乎相同。

这是子选择版本的计划:http://explain.depesz.com/s/eov
这是加入版本的计划: http: //explain.depesz.com/s/aTI

令人惊讶的是,加入版的成本价值略高。

甲骨文

两个计划都是 100% 相同的:

-------------------------------------------------- ----------------------------------
| 身份证 | 操作 | 姓名 | 行 | 字节 |TempSpc| 成本 (%CPU)| 时间 |
-------------------------------------------------- ----------------------------------
| 0 | 选择声明 | | 6815 | 399K| | 273 (2)| 00:00:04 |
| 1 | 哈希唯一 | | 6815 | 399K| 464K| 273 (2)| 00:00:04 |
|* 2 | 哈希连接 | | 6815 | 399K| | 172 (2)| 00:00:03 |
|* 3 | 表访问已满| 书 | 6815 | 166K| | 69 (2)| 00:00:01 |
| 4 | 表访问已满| 作者 | 50000 | 1708K| | 103 (1)| 00:00:02 |
-------------------------------------------------- ----------------------------------

使用时查看统计数据autotrace也没有任何区别。我没有费心去实际创建一个跟踪文件来分析它,因为我不希望在那里看到差异。

如果添加了索引,事情并没有真正改变book.genre。Oracle 坚持使用全表扫描(即使是 100000 行)。可能是因为表格不是很宽,并且很多行适合单页。

PostgreSQL does use the index for both statements but there is still no real difference between the plans.

于 2012-05-18T12:06:05.100 回答
16

两个查询都有效并且返回相同。

您的老师使用了相当过时(尽管仍然有效)的联接语法,并且您使用的结构在某些数据库中效率较低(MySQL例如 )。

如果我是你的老师,我会这样写查询:

SELECT  DISTINCT name
FROM    books b
JOIN    authors a
ON      a.title = b.title
WHERE   b.genre = 'romance'

但如果课程不是针对MySQL优化的,仍然接受您和您老师的查询。

老师说的注意力不就是这个意思吗?

更新:

在数据库引擎级别,两个查询都将被优化为使用相同的计划,除非数据库引擎是MySQL.

MySQL中,您的查询将被强制Authors用作前导表,而对于您的老师的查询,优化器可以根据表的统计信息选择要作为前导的表。

于 2012-05-18T11:57:55.243 回答