0

在大多数情况下,这 2 个 SQL 语句中的哪一个会花费更少的时间?
1)

SELECT table_a.foo,
       table_b.zoo
FROM   table_a,
       table_b
WHERE  table_a.id = table_b.id
       AND table_b.bar = 'something'

2)

SELECT table_a.foo,
       tableb.zoo
FROM   table_a,
       (SELECT *
        FROM   table_b
        WHERE  bar = 'something') AS tableb
WHERE  table_a.id = tableb.id 

或者他们是一样的?
似乎(2)会更快......

4

3 回答 3

5

其他答案和评论是猜测或概括。

真正的答案是它取决于几件事,包括:

  • SQL优化器的实现;您使用的是哪个品牌的 RDBMS?MySQL?微软 SQL 服务器?甲骨文?您应该用适当的品牌标记您的问题。

  • 表定义,包括相关索引。

  • 表的大小,以及与条件匹配的表的子集的大小。

  • 数据大小相对于缓存大小。

  • 等等

正如@Colin'tHart 在评论中提到的那样,SQL 确实应该是一种抽象的声明性语言。因此,您应该能够声明将产生相同结果的两个不同查询,并且 RDBMS 应该将其转换为收集该数据的最佳方式。理论上很好,但实际上,魔术只与软件设计人员为其实现代码的案例数量一样好。

所以你在这个问题的标题中提到的非常基本的通用 sql(效率)主体应该是:

衡量绩效——不要猜测或概括。

要尝试进一步调查此问题,您应该从 SQL 优化器获得一份报告,说明它打算如何访问表和索引以实现您的查询。大多数 RDBMS 产品都有一些称为EXPLAIN的语句的变体,它允许您获取给定查询的此报告。如果 RDBMS 成功地使这个案例抽象化,那么 EXPLAIN 报告对于您显示的两个示例查询应该是相同的。

例如,我对测试 MySQL 数据库尝试了类似的查询。EXPLAIN 显示有一个额外的步骤来运行派生表子查询,然后用于查找匹配的行。

mysql> EXPLAIN SELECT c.*, t.* FROM cast_info c 
JOIN ( SELECT * FROM title WHERE title = 'Star Wars') t ON c.movie_id = t.id\G

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 8
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: c
         type: ref
possible_keys: movie_id
          key: movie_id
      key_len: 4
          ref: t.id
         rows: 9
        Extra: NULL
*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: title
         type: ref
possible_keys: title
          key: title
      key_len: 152
          ref: const
         rows: 8
        Extra: Using where

在没有子查询的情况下进行普通连接有点不同,它仍然首先搜索同一个表,但不必将其视为派生表。

mysql> EXPLAIN SELECT c.*, t.* FROM cast_info c 
JOIN title t ON c.movie_id = t.id WHERE title = 'Star Wars'\G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: ref
possible_keys: PRIMARY,title
          key: title
      key_len: 152
          ref: const
         rows: 8
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: c
         type: ref
possible_keys: movie_id
          key: movie_id
      key_len: 4
          ref: imdb.t.id
         rows: 9
        Extra: NULL

使用 SQL-89(逗号样式)连接语法的处理方式与使用JOIN语法的查询相同:

mysql> EXPLAIN SELECT c.*, t.* FROM cast_info c, title t 
WHERE c.movie_id = t.id AND title = 'Star Wars'\G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: ref
possible_keys: PRIMARY,title
          key: title
      key_len: 152
          ref: const
         rows: 8
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: c
         type: ref
possible_keys: movie_id
          key: movie_id
      key_len: 4
          ref: imdb.t.id
         rows: 9
        Extra: NULL

这只是 MySQL 的结果。另一个 RDBMS 的优化器可能表现不同,它的 EXPLAIN 输出肯定会看起来不同。关键是您有可用的工具来为您自己测试查询的优化计划。

EXPLAIN 报告就是这样一种工具。但是 EXPLAIN 通常只显示优化器计划做什么,而不实际运行查询。您还可以使用探查器工具来运行查询并获得更精确的执行时间度量。可用的分析器工具取决于您的 RDBMS 品牌。

于 2013-10-08T15:09:58.787 回答
0

两者都不会像此查询那样有效:

SELECT
    table_a.foo,
    table_b.zoo
FROM table_a
JOIN table_b
ON table_a.id = table_b.id
AND table_b.bar = 'something'

注意 tableb 上的额外条件是如何在连接条件中而不是where 子句中的,这意味着它在连接时被评估,这可以避免将大量行添加到临时结果集中。

如果它在 where 子句中,它将在进行所有连接后进行评估,因为 where 子句是结果集的过滤器。

于 2013-10-08T13:04:29.837 回答
-1

根据我的理解,查询 1 将花费更少的时间,因为在第二个查询中

SELECT *
        FROM   table_b
        WHERE  bar = 'something'

将首先运行,然后它将与外部查询进行交叉检查。

于 2013-10-08T14:39:33.727 回答