1

StackOverflow 上有一些关于连接交换性的讨论,例如1234。它变得非常复杂,我认为他们中的任何一个都不能在这里回答我的问题。

我经常注意到,当我将查询的 SQL 放入 Access 时,Access 会弄乱我的联接顺序,甚至将LEFT联接更改为联接RIGHT。我通常将外连接写为LEFTs,按逻辑排列连接表的顺序,所以当 Access 搞砸时我不喜欢它。但是现在我注意到查询在设计视图中的表示方式有所不同,我想知道这种差异是否显着。

以下是三个查询:

查询1

SELECT Table1.ID_Table1
FROM Table2 RIGHT JOIN (Table1 LEFT JOIN Table12 
    ON Table1.ID_Table1 = Table12.ID_Table1) ON Table2.ID_Table2 = Table12.ID_Table2;

查询2

SELECT Table1.ID_Table1
FROM Table1 LEFT JOIN (Table2 RIGHT JOIN Table12 
    ON Table2.ID_Table2 = Table12.ID_Table2) ON Table1.ID_Table1 = Table12.ID_Table1;

查询3

SELECT Table1.ID_Table1
FROM Table1 LEFT JOIN (Table12 LEFT JOIN Table2 
    ON Table12.ID_Table2 = Table2.ID_Table2) ON Table1.ID_Table1 = Table12.ID_Table1;

我更喜欢 Query3,因为它具有我提到的逻辑顺序。

当我将这些查询作为 SQL 输入时,Access 将 Query2 的代码更改为与 Query1 相同,并且没有修改 Query1 或 Query3 的代码。当运行这三个查询时(使用非常简单的数据,因此不是结论性的),它们都会产生相同的结果。在设计视图中,Query1 和 Query2 看起来相同,这很好,因为 Access 将 Query2 转换为 Query1。Query3 看起来几乎一样,只是 Table2 和 Table12 之间的关系在 Query1 的视图中表示,而 Query2 在 Query3 的视图中没有表示。

测试 SQL 连接交换性的三个查询

所以我的问题是,Query3 是否等同于 Query1 和 Query2,因此可以安全地忽略设计视图中表关系表示的丢失,或者查询中是否存在操作差异?如果存在差异,是否有连接排序的指导原则?

4

1 回答 1

1

这不是答案,而是不适合评论部分的评论。

...访问与我的连接顺序混淆,甚至将左连接更改为右连接...

好吧,问题是 SQL 是一种声明性语言。与 C、C++、Java、PHP 等命令式语言不同,您无需指定如何检索所需数据,而是告诉 SQL 引擎您需要什么。

当您运行一条 SQL 语句时,数据库引擎将分几个“阶段”处理查询,从解析、缓存、应用参数、改写、计划、优化、执行、流水线、交付等。每个数据库引擎都会添加更多阶段到我提到的那些。

这个问题感兴趣的是改写、计划和优化。

  • 引擎经常会改写 SQL 以更好地管理它。引擎开发人员认为如果“颠倒”编写引擎将更好地管理计划,可能有上百万个理由。你无法真正控制这一点。有时确实有你能理解的正当理由;其他时候它与数据库引擎的内部组织有关。

  • 然后,SQL 计划器会考虑您提到的表、您指定的过滤条件、现有索引、表的统计信息(最新或陈旧),并生成一组计划。所有这些计划都会产生有效的结果。

  • 然后将这组计划提供给优化器,优化器将评估成本(经过的时间、磁盘 I/O、内存消耗、网络带宽等),并将尽其所知选择“最佳方案”。请考虑,据其所知,这可能是相当蹩脚的,这取决于优化器有多弱或多好,而且通常情况下,所选的“最佳”计划可能不是最好的。

现在,实际上,MS-Access 绝对不是最伟大的数据库引擎。您可能认为 SQL 规划器和优化器并不出色。它们完成了自己的工作,但它们是为少量数据而设计的,而不是考虑到数百万行。

最重要的是,不要期望执行计划会与您输入的完全匹配。SQL 是一种声明性语言,优化器可以根据需要自由地重写和处理查询,以高效和安全的方式存储和检索数据。

于 2019-01-23T03:56:14.597 回答