Sql 从中选择与在多个表上选择相比的位置

Sql 从中选择与在多个表上选择相比的位置,sql,Sql,我在学校上数据库课程。老师给了我们一个简单的练习:考虑下面的简单图式: 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) 问题如下: 编写一个

我在学校上数据库课程。老师给了我们一个简单的练习:考虑下面的简单图式:

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"
当我要求解释时,我得到的只是一句“如果你对这门课多加注意,你就会知道为什么”。太棒了


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

两个查询都是有效的,并且返回相同的结果

您的老师使用了非常过时(尽管仍然有效)的联接语法,您使用的构造在某些数据库中效率较低(
MySQL

如果我是你的老师,我会这样写问题:

SELECT  DISTINCT name
FROM    books b
JOIN    authors a
ON      a.title = b.title
WHERE   b.genre = 'romance'
但是,如果课程不是针对MySQL优化的,仍然可以接受您和您老师的询问

难道这不是老师说要注意的意思吗

更新:

在DB引擎级别上,两个查询都将被优化以使用相同的计划,除非DB引擎是
MySQL

MySQL
中,您的查询将被迫使用
Authors
作为前导表,而对于教师的查询,优化器可以根据表的统计信息选择要进行前导的表

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

你的回答是正确的

我猜老师为什么把它标错了,是因为他/她试着在这个问题上练习连接词的用法。但如果这是有意的话,这应该是问题的一部分

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

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

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

编辑 我用50000本书、50000名作者和7种不同的类型创建了一些测试数据进行测试(较小的数字没有真正意义,因为优化器倾向于简单地获取整个表)。该语句将返回7144行

PostgreSQL 执行计划与“join”方法中的一些小更改几乎相同

以下是子选择版本的计划:
以下是加入版本的计划:

令人惊讶的是,join版本的成本值略高

神谕 两个计划完全相同:

-------------------------------------------------------------------------------------- | 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 | -------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------- |Id |操作|名称|行|字节|临时SPC |成本(%CPU)|时间| -------------------------------------------------------------------------------------- |0 | SELECT语句| | 6815 | 399K | | | 273(2)| 00:00:04| |1 | HASH UNIQUE | 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确实对这两个语句都使用了索引,但计划之间仍然没有真正的区别。

编辑注意:这不是作业,我在寻找完整的答案,而不是提示。这是一种有很多答案但其中一个答案比其他答案更正确的情况。Where in通常比先加入然后限制数据的速度慢。如果您使用的是一个有数十万行的表,那么subselect的效率就不会那么高。要证明这一点,请查看两个查询的执行计划。当你阅读执行计划时,你会注意到不同之处。就我个人而言,我会从老师那里拿掉一个非ansii标准联接的例子。@Quassnoi:理解,谢谢:第一个查询由两个查询组成。Queston是:编写查询……RoSCO:我的意思是数据库会考虑一个语句。因为从技术上讲,它是DBMS的一个单一语句。换句话说,显式连接是首选。对吗?@Keyser:从实际的角度来看,它们是一样的,但是显式连接被更多的人认为更可读,更容易调试。我很欣赏你的答案的清晰性!从现在起,我将使用你的语法。如果我可以问一个简单的问题:我使用的语法来自哪里?既然我不是从我的课程中学来的(见:缺乏关注),它一定是从别的地方来的?@Cicada:你是问我你从哪里知道中的
?老实说,我不知道!也许,你在互联网上读到过它,或者在源代码中看到过它,或者别的什么!感谢您的时间和详细回答。
7
类型太少,索引无法使用(如果它们分布均匀)。