Where(隐式内连接)与显式内连接 - 它是否影响索引?

时间:2013-11-19 13:40:06

标签: sql indexing inner-join implicit

查询

SELECT * from table_a, b WHERE table_a.id = b.id AND table_a.status ='success'  

SELECT * from a WHERE table_a.status ='success' JOIN b ON table_a.id = b.id

不知何故,我倾向于在table_a上为顶部形式创建一个索引(id,status) 而我对底部形式的自然倾向是创建两个单独的指数, table_a上的id和status。

这两个查询实际上是一样的吧?你会以同样的方式索引吗? 你如何索引table_a(假设这是系统中唯一存在的查询,以避免其他考虑因素)?一个或两个指数?

3 个答案:

答案 0 :(得分:3)

“传统样式”和SQL 92样式内部联接在语义上是等效的,大多数DBMS会将它们视为相同(例如,Oracle)。他们将对两种形式使用相同的执行计划(尽管如此,这取决于实现,并且不受任何标准的保证)。

因此,索引在两种形式中也以相同的方式使用。

与您使用的语法无关,适当的索引策略依赖于实现:某些DBMS(例如Postgres)通常更喜欢单列索引,并且可以非常有效地组合它们,其他的(如Oracle)可以从组合(甚至覆盖)索引(尽管两种形式当然都适用于DBMS)。

关于你的例子的语法,第二个WHERE子句的位置让我感到很惊讶。

以下两个查询在大多数DBMS中以相同的方式处理:

SELECT * FROM table_a, b WHERE table_a.id = b.id AND table_a.status ='success'  

SELECT * FROM a JOIN b ON table_a.id = b.id WHERE table_a.status ='success' 

但是,你的第二个查询会在FROM子句中移动WHERE子句,这在我的视图中不是有效的SQL。

快速检查

SELECT * from a WHERE table_a.status ='success' JOIN b ON table_a.id = b.id

确认:MySQL 5.5,Postgres 9.3和Oracle 11g都会产生语法错误。

答案 1 :(得分:0)

应优化两个查询以执行相同的方式;但是,连接语法符合ANSI标准,不推荐使用旧版本。就索引使用而言,您只想触摸一次表(索引)。您正在使用的RDBMS和表格设计将确定是否需要在覆盖索引中包含PRIMARY KEY(假设您的示例中代表ID)。此外,SELECT *可能包括也可能不包括在内;最好使用特定的列名。

答案 2 :(得分:0)

嗯,你排除了其他问题,但仍有一些悬而未决的问题:特别是有关数据分发的问题。例如。如何将行数WHERE table_a.status ='success'与table_b的表大小进行比较?根据优化者的估计,必须做出两个重要的决定:

  1. 使用哪种连接算法(嵌套循环;散列或排序/合并)
  2. 以哪种顺序处理表格?
  3. 不幸的是,这些决定会影响索引(并受索引影响!)

    示例:假设只有一行WHERE table_a.status ='success'。在table_a.status上有一个索引可以快速找到该行。接下来,我们希望在table_b.id上有一个索引,以使用嵌套循环连接快速查找相应的行。考虑到您选择*将其他列包含在这些索引中没有任何意义(不考虑系统中的任何其他查询)。

    但是现在假设你没有table_a.status上的索引,但是在table_a.id上,并且这个表与table_b相比是巨大的。为了演示,我们假设table_b只有一行(当然是极端情况)。现在最好去table_b,获取所有行(只有一行),然后使用索引从table_a中获取相应的行。您看到索引如何影响连接顺序? (对于此示例中的嵌套循环连接)

    这只是事物互动的一个简单例子。大多数数据库都有三种连接算法可供选择(MySQL除外)。

    如果创建三个提到的索引并查看数据库执行连接的方式(解释计划),您将注意到为查询选择的特定join-algo / join-order仍然没有使用一个或两个索引。从理论上讲,你可以删除这些索引。但是,请记住,优化程序根据他可用的统计信息做出决策,并且优化程序估计可能是错误的。

    您可以在我的网站上找到有关索引联接的更多信息:http://use-the-index-luke.com/sql/join