非常基本的通用sql(效率)主体

ino*_*nor 0 sql performance select join

在大多数情况下,这两个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'
Run Code Online (Sandbox Code Playgroud)

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 
Run Code Online (Sandbox Code Playgroud)

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

Bil*_*win 5

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

真正的答案是它取决于几个方面,包括:

  • SQL优化器的实现; 您使用的是哪个品牌的RDBMS?MySQL的?Microsoft SQL Server?甲骨文?您应该使用适当的品牌标记您的问题.

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

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

  • 相对于缓存大小的数据大小.

  • 等等

确实,SQL 应该是一个抽象的声明性语言,如@Colin'tHart在评论中提到的那样.因此,您应该能够声明两个不同的查询,这些查询将产生相同的结果,并且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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

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

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