mysql连接的计算顺序是什么?

wb1gzix0  于 2021-06-15  发布在  Mysql
关注(0)|答案(7)|浏览(284)

我有以下疑问:

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;

我有以下问题:
using语法与on语法同义吗?
这些连接是从左到右计算的吗?换句话说,这个查询是否说:x=公司加入用户;y=x加入工作;z=y加入用户帐户;
如果问题2的答案是肯定的,那么可以安全地假设companies表有companyid、userid和jobid列吗?
我不明白where子句在companies表中引用别名“j”时,如何使用它来选取行
任何帮助都将不胜感激!

mwngjboj

mwngjboj1#

使用(fieldname)是对table1.fieldname=table2.fieldname的一种速记方式。
sql没有定义连接的“顺序”,因为这不是语言的本质。显然,必须在语句中指定顺序,但是内部联接可以被认为是可交换的:您可以按任何顺序列出它们,您将得到相同的结果。
这就是说,当构建一个选择。。。连接,尤其是包含左连接的连接,我发现将第三个连接视为将新表连接到第一个连接的结果,将第四个连接视为连接第二个连接的结果,依此类推是有意义的。
更罕见的是,指定的顺序可以影响查询优化器的行为,因为它影响启发式的方式。
不需要。按照查询的组装方式,它要求公司和用户都有companyid,jobs有userid和jobid,useraccounts有userid。但是,只有一个公司或用户需要一个userid才能使join工作。
where子句使用jobs表提供的列过滤整个结果,即所有联接的列。

ojsjcaue

ojsjcaue2#

下面是一个更详细的答案 JOIN 优先。就你而言 JOIN 都是交换的。让我们在他们不在的地方试试。
生成架构:

CREATE TABLE users (
  name text
);

CREATE TABLE orders (
  order_id text,
  user_name text
);

CREATE TABLE shipments (
  order_id text,
  fulfiller text
);

添加数据:

INSERT INTO users VALUES ('Bob'), ('Mary');

INSERT INTO orders VALUES ('order1', 'Bob');

INSERT INTO shipments VALUES ('order1', 'Fulfilling Mary');

运行查询:

SELECT *
  FROM users
       LEFT OUTER JOIN orders
       ON orders.user_name = users.name
       JOIN shipments
       ON shipments.order_id = orders.order_id

结果:
只返回bob行
分析:
在这个查询中 LEFT OUTER JOIN 首先评估 JOIN 根据试验的综合结果进行了评价 LEFT OUTER JOIN .
第二个查询:

SELECT *
  FROM users
       LEFT OUTER JOIN (
         orders
         JOIN shipments
         ON shipments.order_id = orders.order_id)
         ON orders.user_name = users.name

结果:
一行表示bob(包含履行数据),一行表示mary,其中null表示履行数据。
分析:
括号更改了求值顺序。
更多的mysql文档在https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html

epfja78i

epfja78i3#

我无法回答有关使用语法的问题。真奇怪。我以前从来没见过,总是用on子句来代替。
但我可以告诉你的是,连接操作的顺序是由查询优化器在构建其查询计划时根据优化启发式系统动态确定的,其中一些是:
联接是在主键字段上执行的吗?如果是这样的话,它在查询计划中会获得高优先级。
联接是在外键字段上执行的吗?这也得到了高度重视。
联接字段上是否存在索引?如果是这样的话,就降低优先级。
是否对where子句中的字段执行联接操作?where子句表达式是否可以通过检查索引(而不是执行表扫描)进行计算?这是一个主要的优化机会,因此它获得了一个主要的优先级提升。
连接列的基数是多少?具有高基数的列为优化器提供了更多的机会来区分错误匹配(那些不满足where子句或on子句的匹配),因此高基数联接通常在低基数联接之前处理。
联接表中实际有多少行?与一个只有100个值的表相比,与一个有1000万行的表相比,连接一个只有100个值的表会产生更少的数据爆炸。
不管怎样。。。关键是。。。查询执行计划中有很多变量。如果您想了解mysql如何优化其查询,请使用explain语法。
下面是一篇好文章:
http://www.informit.com/articles/article.aspx?p=377652
编辑时:
回答您的第四个问题:您没有查询“companies”表。您正在查询from和using子句中所有四个表的联接叉积。
“j.jobid”别名只是该联接表集合中某一列的完全限定名。

dl5txlt9

dl5txlt94#

我不确定的对vs使用部分(虽然这个网站说他们是相同的)
至于排序问题,它完全是实现(可能是查询)特定的。mysql很可能在编译请求时选择一个顺序。如果要强制执行特定顺序,则必须“嵌套”查询:

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

至于第4部分:where子句限制了jobs表中有资格连接的行。因此,如果有行由于匹配的userid而加入,但是没有正确的jobid,那么它们将被忽略。

mnowg1ta

mnowg1ta5#

看到了吗http://dev.mysql.com/doc/refman/5.0/en/join.html
从这里开始读:
加入MySQL5.0.12中的处理更改
从MySQL5.0.12开始,根据sql:2003 standard. 目标是使mysql的语法和语义与自然连接和连接保持一致。。。使用依据sql:2003. 但是,联接处理中的这些更改可能会导致某些联接的输出列不同。另外,一些在旧版本中似乎正常工作的查询必须重写以符合标准。
这些变化主要有五个方面:
mysql确定自然或使用join操作的结果列(从而确定整个from子句的结果)的方式。
展开select*并选择tbl\u name.*进入所选列的列表。
在自然连接或使用连接中解析列名。
将自然连接或使用连接转换为连接。。。打开。
在联接条件下列名的解析。。。打开。

j5fpnvbx

j5fpnvbx6#

在mysql中,询问查询优化器计划做什么通常很有趣,包括:

EXPLAIN SELECT [...]

参见“7.2.1使用explain优化查询”

oewdyzsn

oewdyzsn7#

1) using与on不完全相同,但它是两个表都有一个与您要加入的列同名的列的缩写。。。请参见:http://www.java2s.com/tutorial/mysql/0100__table-join/thekeywordusingcanbeusedasareplacementfortheonkeywordduringthetablejoins.htm
在我看来,阅读起来比较困难,所以我要去把连接词拼出来。
3) 这个问题不清楚,但我猜不清楚。
2) 假设您是通过其他表(并非所有表都直接在公司上)联接的,那么此查询中的顺序确实很重要。。。请参见下面的比较:
原产地:

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

我认为它可能暗示:

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

你可以在这里切换加入jobs和usersaccounts的线路。
如果所有人都加入公司,会是什么样子:

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

这不符合逻辑。。。除非每个用户都有自己的公司。
4.)sql的神奇之处在于,您只能显示某些列,但它们都是用于排序和筛选的列。。。
如果你回来

SELECT c.*, j.jobid....

您可以清楚地看到它在过滤什么,但是数据库服务器并不关心您是否输出一行进行过滤。

相关问题