为什么SQL ANSI-92标准不比ANSI-89更好地采用?

时间:2008-12-02 14:56:45

标签: sql join ansi-sql ansi-92

在我所工作的每家公司,我发现人们仍在使用ANSI-89标准编写SQL查询:

select a.id, b.id, b.address_1
from person a, address b
where a.id = b.id

而不是ANSI-92标准:

select a.id, b.id, b.address_1
from person a
inner join address b
on a.id = b.id

对于这样一个非常简单的查询,可读性没有太大差异,但是对于大型查询,我发现将我的连接条件分组并列出表格可以更容易地看到我在哪里可能遇到问题加入,让我在WHERE子句中保留所有过滤。更不用说我觉得外连接比Oracle中的(+)语法更直观。

当我尝试向人们传播ANSI-92时,使用ANSI-92而不是ANSI-89有什么具体的性能优势吗?我会自己尝试一下,但我们这里的Oracle设置不允许我们使用EXPLAIN PLAN - 不希望人们尝试优化他们的代码,是吗?

16 个答案:

答案 0 :(得分:75)

根据Peter Gulutzan和Trudy Pelzer的“SQL性能调优”,在他们测试的六个或八个RDBMS品牌中,SQL-89与SQL-92样式连接的优化或性能没有区别。可以假设大多数RDBMS引擎在优化或执行查询之前将语法转换为内部表示,因此人类可读的语法没有区别。

我也尝试传播SQL-92语法。它获得批准后十六年,人们开始使用它的时间已经过去了!所有SQL数据库品牌现在都支持它,因此没有理由继续使用令人厌恶的(+) Oracle语法或*= Microsoft / Sybase语法。

至于为什么很难打破SQL-89习惯的开发者社区,我只能假设程序员有一个庞大的“金字塔基础”,他们通过复制和编码来编码。粘贴,使用书籍,杂志文章或其他代码库中的古代例子,这些人不抽象地学习新的语法。有些人模式匹配,有些人死记硬背。

我逐渐看到人们比以前更频繁地使用SQL-92语法。自1994年以来,我一直在线回答SQL问题。

答案 1 :(得分:16)

ANSI092标准包含一些非常令人发指的语法。 Natural Joins是一个,USING子句是另一个。恕我直言,在表中添加一列不应该破坏代码,但是NATURAL JOIN会以最令人震惊的方式中断。打破“最好”的方法是编译错误。例如,如果您在某处选择SELECT *,则添加将无法编译。失败的下一个最佳方法是运行时错误。它更糟糕,因为你的用户可能会看到它,但它仍然会给你一个很好的警告,你已经破坏了一些东西。如果您使用ANSI92并使用NATURAL连接编写查询,它将不会在编译时中断,并且它不会在运行时中断,查询将突然开始产生错误的结果。这些类型的错误是阴险的。报告出错,可能是财务披露不正确。

对于那些不熟悉NATURAL连接的人。它们在两个表中存在的每个列名上连接两个表。当你有一个4列密钥并且你厌倦了键入它时,这真的很酷。当Table1有一个名为DESCRIPTION的预先存在的列并且你向Table2添加一个新列时,问题就出现了,哦我不知道,像mmm这样无关紧要的描述,现在你要加入VARCHAR2上的两个表了(1000)自由形式的领域。

除了上述问题之外,USING子句还可能导致完全歧义。在另一个SO post中,有人展示了这个ANSI-92 SQL并请求帮助阅读它。

SELECT c.* 
FROM companies AS c 
JOIN users AS u USING(companyid) 
JOIN jobs AS j USING(userid) 
JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123

这完全是模棱两可的。我在公司和用户表中都放了一个UserID列,没有任何抱怨。如果公司中的UserID列是最后一个修改该行的人的ID,该怎么办?

我是认真的,有谁能解释为什么这种歧义是必要的?为什么它直接纳入标准?

我认为Bill是正确的,有大量的开发人员通过编码复制/粘贴。事实上,我可以承认,就ANSI-92而言,我是一个人。我见过的每个例子都显示多个连接嵌套在括号中。诚实,这使得在sql中挑选表格充其量是困难的。但后来SQL92 evangilist解释说实际上会强制连接顺序。耶稣...我见过的所有复制贴纸现在实际上都在强制加入订单 - 这项工作95%的时间最好留给优化者,特别是复制/贴纸。

Tomalak说得对,

  

人们不会仅仅切换到新语法   因为它在那里

它必须给我一些东西,我看不到好处。如果有上行空间,那么负面影响就是信天翁太大而不容忽视。

答案 2 :(得分:14)

有几个原因浮现在脑海中:

  • 人们习惯这样做
  • 人们很懒,喜欢“旧式”连接,因为它们涉及的打字较少
  • 初学者经常围绕SQL-92连接语法包围他们的问题
  • 人们不会因为它存在而切换到新语法
  • 人们没有意识到新的(如果你想称之为)语法的好处,主要是它使你能够在进行外连接之前过滤表,而不是之后什么时候有WHERE子句。

就我而言,我使用SQL-92语法完成所有连接,并且尽可能地转换代码。它是更清晰,更易读和更强大的方式。但是当他们认为在不改变查询结果的情况下更多打字工作会伤害他们时,很难说服某人使用新风格。

答案 3 :(得分:10)

回应上面的NATURAL JOIN和USING帖子。

为什么你会看到需要使用它们 - 它们在ANSI-89中不可用,并且被添加为ANSI-92,因为我只能看到它作为捷径。

我永远不会将联接留给机会,并且总是指定表/别名和id。

对我而言,唯一的出路就是ANSI-92。它更冗长,ANSI-89粉丝不喜欢它的语法,但它巧妙地将你的JOINS与你的过滤分开。

答案 4 :(得分:5)

首先让我说在SQL Server中,外连接语法(* =)不会始终提供正确的结果。有时它将其解释为交叉连接而不是外连接。所以,有充分的理由停止使用它。并且外部联接语法是一个不推荐使用的功能,并且不会在SQL Server 2008之后的SQL Server的下一个版本中。您仍然可以执行内部联接,但为什么地球上有人想要?它们不清楚,难以维护。你不容易知道什么是连接的一部分,什么才是真正的where子句。

我认为你不应该使用旧语法的一个原因是理解连接以及它们做什么和不做什么对于任何编写SQL代码的人来说都是关键的一步。如果不彻底了解联接,则不应编写任何SQL代码。如果您理解它们,您可能会得出结论,ANSI-92语法更清晰,更易于维护。我从来没有遇到过一个SQL专家,他没有使用ANSI-92语法而不喜欢旧语法。

我遇到或处理过的使用旧代码的大多数人,在查询数据库时确实不理解联接,从而遇到麻烦。这是我个人的经历,所以我不是说它总是如此。但作为一名数据专家,多年来我不得不解决这些垃圾过多的问题。

答案 5 :(得分:4)

我在学校教过ANSI-89,并在工业界工作了几年。然后我离开了DBMS的神话般的世界8年。但后来我回来了,这个新的ANSI 92的东西正在被教。我已经学习了Join On语法,现在我实际上教了SQL,我推荐使用新的JOIN ON语法。

但是我看到的缺点是相关的子查询似乎没有任何意义,因为ANSI 92连接。当连接信息包含在WHERE中并且相关子查询在WHERE中“加入”时,所有似乎都是正确且一致的。在ANSI 92表连接条件不在WHERE和子查询“join”中,语法似乎不一致。另一方面,试图“修复”这种不一致可能会使情况变得更糟。

答案 6 :(得分:2)

我肯定不知道答案。这是一场宗教战争(比Mac-Pc或其他人的程度低一些)

一个猜测是,直到最近,Oracle(以及其他供应商)也没有采用ANSI-92标准(我认为它是在Oracle v9或其附近),因此对于DBA / Db开发人员而言在那些仍在使用这些版本的公司(或希望代码可以在可能使用这些版本的服务器上移植,他们必须坚持旧标准......

真的很遗憾,因为新的连接语法更具可读性,并且旧语法在几个记录良好的场景中生成错误(不正确)的结果。

  • 具体来说,外部连接在那里 是条件过滤谓词 来自的非联接相关列 桌子在“外”的一面 加入。

答案 7 :(得分:2)

惯性和实用性。

ANSI-92 SQL就像触摸式打字。从某种理论上来说,它可能会让某一天的一切变得更好,但我现在可以用四根手指快速打字。我需要倒退才能前进,不能保证会有回报。

编写SQL约占我工作的10%。如果我需要ANSI-92 SQL来解决ANSI-89 SQL无法解决的问题,那么我将使用它。 (事实上​​,我在Access中使用它。)如果一直使用它会帮助我更快地解决现有问题,我会花时间去理解它。但我可以在不考虑语法的情况下推出ANSI-89 SQL。我得到了解决问题的报酬 - 考虑SQL语法是浪费我的时间和雇主的钱。

有一天,年轻的Grasshopper,你将捍卫你对年轻人的使用ANSI-92 SQL语法,抱怨你应该使用SQL3(或其他)。然后你会明白的。 : - )

答案 8 :(得分:2)

我有一个最初为SQL Server 6.5编写的查询,它不支持SQL 92连接语法,即

select foo.baz
from foo
  left outer join bar
  on foo.a = bar.a

改为写成

select foo.baz
from foo, bar
where foo.a *= bar.a

查询已经存在了一段时间,并且累积了相关数据以使查询运行得太慢,大约需要90秒才能完成。当这个问题出现时,我们已经升级到SQL Server 7。

在使用索引和其他Easter-egging之后,我将连接语法更改为符合SQL 92。查询时间减少到3秒。

有充分的理由转换。

here转发。

答案 9 :(得分:1)

我可以从普通开发人员的角度回答,知道足够的SQL来理解这两种语法,但是每次我需要时仍然使用Google搜索插入的确切语法... :-P(我不做SQL整天,只是不时修复一些问题。)

实际上,我发现第一种形式更直观,两个表之间没有明显的层次结构。事实上,我学习了可能有旧书的SQL,显示了第一种形式,可能没有帮助...... ;-)
我在Google上的 sql select 搜索中找到的第一个引用(主要为我返回法语答案......)首先显示旧表单(然后解释第二个表单)。

只是给出一些关于“为什么”问题的提示...... ^ _ ^我应该读一篇关于这个主题的好的,现代的书(DB不可知)。如果有人有建议......

答案 10 :(得分:1)

我不能代表所有的学校,但是在我的大学里,当我们学习本课程的SQL模块时,他们并没有教授ANSI-92,他们在旧的VAX系统上教授ANSI-89!直到我开始在Access中使用查询设计器构建一些查询然后深入研究SQL代码之前,我才接触到ANSI-92。意识到我不知道它是如何完成连接的,或者语法的含义我开始深入挖掘所以我能理解它。

鉴于可用文档在很多情况下并不完全直观,并且人们倾向于坚持他们所知道的内容,并且在许多情况下不努力学习他们需要的东西以获得他们的工作完成后,很容易理解为什么采用这么长时间。

当然,有些技术布道者喜欢修补和理解,而且往往是采用“更新”原则并尝试转换其余部分的那些类型。

奇怪的是,在我看来,许多程序员走出学校并停止前进;认为因为这是他们所教授的,所以这就是它的完成方式。直到你脱掉你的眼罩,你才意识到学校只是为了教你基础知识并给你足够的理解来自己学习其余的东西,而且你几乎没有弄清楚要知道的东西;现在继续这条道路是你的工作。

当然,根据我的经验,这只是我的观点。

答案 11 :(得分:1)

1)写入OUTER JOIN的标准方式,而不是* =或(+)=

2)自然加入

3)依赖于数据库引擎,ANSI-92趋势更加优化。

4)手动优化:

假设我们有下一个语法(ANSI-89):

(1)select * from TABLE_OFFICES to,BIG_TABLE_USERS btu
where to.iduser=tbu.iduser and to.idoffice=1

可以写成:

(2)select * from TABLE_OFFICES to
inner join BIG_TABLE_USERS btu on to.iduser=tbu.iduser
where to.idoffice=1

但也如:

(3)select * from TABLE_OFFICES to
inner join BIG_TABLE_USERS btu on to.iduser=tbu.iduser and to.idoffice=1

所有这些(1),(2),(3)返回相同的结果,但它们的优化方式不同,它取决于数据库引擎,但大多数都是:

  • (1)由数据库引擎决定优化。
  • (2)它连接两个表,然后按办公室进行过滤。
  • (3)它使用idoffice过滤BIG_TABLE_USERS,然后加入两个表。

5)更长的查询不那么混乱。

答案 12 :(得分:1)

人们使用ANSI-89的原因来自我对老少年程序员和受训人员以及应届毕业生的实践经验:

  • 他们从他们看到的现有代码(而不是书籍)中学习SQL,并从代码
  • 学习ANSI-89
  • ANSI-89因为输入较少
  • 他们没有考虑它并使用一种或其他风格,甚至不知道哪一种被认为是新的或旧的,也不关心
  • 代码也是与下一个维护代码的程序员沟通的想法不存在。他们认为他们与电脑交谈,电脑也不在乎。
  • “清洁编码”的艺术未知
  • 特别是对编程语言和SQL的了解非常糟糕,以至于他们将他们在别处找到的内容复制并粘贴在一起
  • 个人偏好

我个人更喜欢ANSI-92并更改我在ANSI-89语法中看到的每个查询,有时只是为了更好地理解手头的SQL语句。但我意识到,与我合作的大多数人都不够熟练,无法在多个表格上编写联接。他们编写尽可能好的代码,并在第一次遇到SQL语句时使用他们记住的内容。

答案 13 :(得分:0)

Oracle完全没有实现ANSI-92。我遇到了一些问题,尤其是因为Oracle Apps中的数据表具有非常好的列。如果联接中的列数超过大约1050列(这在应用程序中非常容易),那么您将得到这个虚假错误,这完全没有逻辑意义:

ORA-01445: cannot select ROWID from a join view without a key-preserved table.

重新编写查询以使用旧式连接语法会使问题消失,这似乎直接指责ANSI-92连接的实现。

在我遇到这个问题之前,我是ASNI-92的坚定推动者,因为它减少了意外交叉连接的可能性,这对于旧式语法来说太容易了。

然而,现在我发现要坚持下去要困难得多。他们指出甲骨文的糟糕实施并说“我们会按照自己的方式行事,谢谢。”

答案 14 :(得分:0)

以下是比较SQL-89和SQL-92以及清除其他答案中的一些误解的几点。

  1. NATURAL JOINS是一个可怕的想法。它们是隐含的,它们需要有关该表的元信息。关于SQL-92的任何内容都不需要使用它们,只需忽略它们即可。它们与此讨论无关。
  2. USING是一个好主意,它有两个效果:
    1. 它在equijoin的结果集上只生成一列。
    2. 它强制执行健全和合理的惯例。在SQL-89中,您有人在两个表上编写列id。加入表后,这变得模糊不清,需要显式别名。此外,连接上的id几乎肯定有不同的数据。如果您将此人加入公司,则现在必须将一个id别名为person_id,将一个id别名为company_id,否则该联接会产生两个不明确的列。使用表的代理键的全局唯一标识符是USING的标准奖励惯例。
  3. SQL-89语法是隐式CROSS JOINCROSS JOIN不会减少集合,它会隐式增长它。 FROM T1,T2FROM T1 CROSS JOIN T2相同,会产生笛卡尔连接,这通常不是您想要的。将选择权降低到一个遥远的WHERE条件意味着您更有可能在设计过程中犯错误。
  4. SQL-89 ,和SQL-92显式JOIN具有不同的优先级。 JOIN具有更高的优先级。更糟糕的是,some databases like MySQL got this wrong for a very long time.。所以混合这两种风格是一个坏主意,今天更流行的风格是SQL-92风格。

答案 15 :(得分:0)

新的SQL标准继承了之前标准中的所有内容,即。兼容性'的枷锁。所以“老”' /'以逗号分隔' /'不合格' join样式是完全有效的SQL-92 sytax。

现在,我认为SQL-92的NATURAL JOIN是您需要的唯一连接。例如,我认为它优于inner join,因为它不会生成重复的列 - SELECT子句中没有更多的范围变量来消除列的歧义!但我无法改变每一个人的心灵,所以我需要与编码人员合作,他们将继续采用我个人认为的传统连接方式(他们甚至可能将范围变量称为'别名'!)。这是团队合作的本质,而不是在真空中运作。

对SQL语言的一个批评是,使用许多语义等效的语法(一些使用关系代数,一些使用关系演算)可以获得相同的结果,其中选择最佳' ;一个简单归结为个人风格。所以我对这种老式的'#s;和INNER一样加入。我是否花时间将它们重写为NATURAL取决于上下文。