我有以下查询:

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;

我有以下问题:

  1. USING 语法与 ON 语法同义吗?
  2. 这些连接是从左到右评估的吗?换句话说,这个查询是否说:x = 公司加入用户;y = x 加入工作;z = y 加入用户帐户;
  3. 如果问题 2 的答案是肯定的,那么可以安全地假设 Companies 表具有 companyid、userid 和 jobid 列吗?
  4. 我不明白当 WHERE 子句引用别名“j”时,如何使用 WHERE 子句在 Companies 表上选择行

任何帮助,将不胜感激!

有帮助吗?

解决方案

  1. USING (fieldname) 是 ON table1.fieldname = table2.fieldname 的简写方式。

  2. SQL 没有定义执行 JOINS 的“顺序”,因为它不是该语言的本质。显然,必须在语句中指定顺序,但 INNER JOIN 可以被认为是可交换的:您可以按任意顺序列出它们,您将得到相同的结果。

    也就是说,在构建 SELECT 时...JOIN,特别是包含 LEFT JOIN 的 JOIN,我发现将第三个 JOIN 视为将新表连接到第一个 JOIN 的结果,将第四个 JOIN 视为连接第二个 JOIN 的结果,等等是有意义的。

    更罕见的是,指定的顺序会影响查询优化器的行为,因为它影响启发式方法。

  3. 不。查询的组装方式要求公司和用户都有一个 companyid,jobs 有一个 userid 和一个 jobid,useraccounts 有一个 userid。但只有其中一家公司 或者 用户需要一个用户 ID 才能使 JOIN 正常工作。

  4. WHERE 子句正在过滤整个结果——即所有连接的列——使用作业表提供的列。

其他提示

我无法回答有关USING语法的问题。那真是怪了。我以前从未见过它,总是使用ON子句。

可以告诉你的是,JOIN操作的顺序是由查询优化器根据优化启发式系统构建其查询计划时动态确定的,其中一些是:

  1. 是否在主键字段上执行了JOIN?如果是这样,则在查询计划中获得高优先级。

  2. 是否在外键字段上执行了JOIN?这也是高优先级。

  3. 联接字段中是否存在索引?如果是这样,请优先考虑。

  4. 是否在WHERE子句中的字段上执行了JOIN操作?可以通过检查索引(而不是通过执行表扫描)来评估WHERE子句表达式吗?这是一个主要的优化机会,因此它会成为一个重要的优先事项。

  5. 联合专栏的基数是多少?具有高基数的列为优化器提供了更多机会来区分错误匹配(不满足WHERE子句或ON子句的那些),因此通常在低基数连接之前处理高基数连接。

  6. 连接表中有多少实际行?加入一个只有100个值的表将比创建一千万行的表加入更少的数据爆炸。

  7. 无论如何......关键是......有很多变量进入查询执行计划。如果您想了解MySQL如何优化其查询,请使用EXPLAIN语法。

    这是一篇很好的文章:

    http://www.informit.com/articles/article.aspx? p值= 377652个


    ON EDIT:

    回答你的第四个问题:你不是在询问“公司”。表。您正在查询FROM和USING子句中 ALL 四个表的联接交叉产品。

    “j.jobid”别名只是该连接表集合中其中一列的完全限定名称。

在MySQL中,通过以下方式询问查询优化器通常会有什么兴趣:

EXPLAIN SELECT [...]

请参阅“7.2.1使用EXPLAIN优化查询”

http://dev.mysql.com/doc/refman/5.0/en/join.html

并从这里开始阅读:


MySQL 5.0.12 中的连接处理更改

从 MySQL 5.0.12 开始,自然连接和使用 USING 的连接(包括外连接变体)根据 SQL:2003 标准进行处理。目标是使 MySQL 的语法和语义与 NATURAL JOIN 和 JOIN ...根据 SQL:2003 使用。但是,连接处理中的这些更改可能会导致某些连接产生不同的输出列。此外,一些在旧版本中似乎可以正常工作的查询必须重写以符合标准。

这些变化主要有五个方面:

  • MySQL 确定 NATURAL 或 USING 连接操作的结果列(以及整个 FROM 子句的结果)的方式。

  • 将 SELECT * 和 SELECT tbl_name.* 扩展为选定列的列表。

  • NATURAL 或 USING 连接中列名的解析。

  • 将 NATURAL 或 USING 连接转换为 JOIN ...在。

  • JOIN 的 ON 条件下的列名解析...在。

我不确定ON和USING部分(虽然这个网站说它们是相同的)

至于排序问题,它完全实现(可能是查询)具体。 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表中的哪些行有资格加入。因此,如果由于匹配的用户标识而存在会加入的行但没有正确的jobid,那么它们将被省略。

1)使用与on不完全相同,但它是短手,其中两个表都有一个与你加入的名称相同的列...请参阅: http://www.java2s.com/Tutorial/MySQL/0100__Table-Join/ThekeywordUSINGcanbeusedasplacementmentonhekeywordduringthetableJoins.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

你可以切换你加入职位的行&amp; 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....  

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

以下是 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 ,并在 LEFT OUTER JOIN 的复合结果上评估 JOIN 。 / p>

第二次查询:

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top