9

在这种情况下,我通过子查询加入并希望将 deptid 传递给加入的子查询,但我收到“D 未定义”错误消息。

SELECT * 
    FROM(   
        SELECT D.name AS deptname,D.id AS deptid,WT.sortposition AS deptsortposition 
        FROM departments D JOIN web_taxonomy WT ON (WT.deptid=D.id AND WT.classid=0) 
        WHERE D.web=1
        ORDER BY sortposition
    ) AS D
    LEFT JOIN (
        SELECT C.name AS classname,C. id AS classid,C.department,WT.sortposition AS classsortposition,WT.deptid
        FROM classes C
        JOIN web_taxonomy WT ON (WT.classid=C.id AND WT.subclassid=0 AND WT.deptid=D.deptid) 
        WHERE web=1 ORDER BY classsortposition  
    ) AS C ON (C.department=D.deptid)

有什么方法可以传递类似于我在上面的强标签中包装的参考吗?

编辑:我犯了一个错误,最初留在了工作查询中,只是添加了我想要运行的部分。本质上,我想通过仅获取与 D 子查询表中发现的共享相同 deptid 的行来最小化连接子查询的大小。

4

2 回答 2

13

您不能在您正在别名的子查询中使用您的别名“D”。

这应该有效(仅在第一个子查询中使用 X 而不是 D - 不是绝对必要的,但有助于提高可读性 - 并将对 D 的引用移动到第二个子查询之外):

SELECT * 
    FROM(   
        SELECT 
           X.name AS deptname
           , X.id AS deptid
           , WT.sortposition AS deptsortposition 
        FROM departments X 
        JOIN web_taxonomy WT ON (WT.deptid=X.id AND WT.classid=0) 
        WHERE X.web=1
        ORDER BY sortposition
    ) AS D  -- this is available to objects referencing this alias
    LEFT JOIN (
        SELECT 
           C.name AS classname
           , C. id AS classid
           , C.department
           , WT.sortposition AS classsortposition
           , WT.deptid
        FROM classes C JOIN web_taxonomy WT 
        ON WT.classid=C.id AND WT.subclassid=0
        WHERE web=1 ORDER BY classsortposition  
    ) AS C ON C.department=D.deptid AND C.deptid = D.deptid -- i.e. here
于 2013-11-11T16:28:18.260 回答
7

我认为您根本不需要进行子查询:

SELECT D.name AS deptname, D.id AS deptid, WT1.sortposition AS deptsortposition,
  C.name AS classname, C.id AS classid, C.department, 
  WT2.sortposition AS classsortposition, WT2.deptid
FROM departments AS D
JOIN web_taxonomy AS WT1 ON (WT1.deptid=D.id AND WT1.classid=0)
LEFT OUTER JOIN web_taxonomy AS WT2 ON (WT2.deptid=D.id AND WT2.subclassid=0)
LEFT OUTER JOIN classes AS C ON (C.id=WT2.classid AND C.department=WT2.deptid);

WT1 的连接应该受益于索引:

ALTER TABLE web_taxonomy
  ADD KEY wt_dept_class (deptid, classid),
  ADD KEY wt_dept_subclass (deptid, subclassid);

与类的连接使用该表的 PRIMARY 键索引。

这是此查询的 EXPLAIN 输出:

+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+-----------------------+
| id | select_type | table | type   | possible_keys            | key           | key_len | ref              | rows | Extra                 |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+-----------------------+
|  1 | SIMPLE      | D     | ALL    | PRIMARY,id               | NULL          | NULL    | NULL             |    1 | NULL                  |
|  1 | SIMPLE      | WT1   | ref    | dept_class,dept_subclass | dept_class    | 10      | test.D.id,const  |    1 | Using index condition |
|  1 | SIMPLE      | WT2   | ref    | dept_class,dept_subclass | dept_subclass | 10      | test.D.id,const  |    1 | Using where           |
|  1 | SIMPLE      | C     | eq_ref | PRIMARY,id               | PRIMARY       | 8       | test.WT2.classid |    1 | Using where           |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+-----------------------+

说实话,我不得不稍微编辑一下 EXPLAIN 报告以显示该结果。我用零行的表进行了测试,所以优化器错误地为 WT2 选择了 dept_class 索引。如果您使用真实数据进行测试,我认为它会正确选择 dept_subclass 索引。


我尝试了您的查询,并稍作修改以解决 D.deptid 上的错误:

SELECT *
FROM(
  SELECT D.name AS deptname,D.id AS deptid,WT.sortposition AS deptsortposition
  FROM departments D JOIN web_taxonomy WT ON (WT.deptid=D.id AND WT.classid=0)
  WHERE D.web=1
  ORDER BY sortposition
) AS D
LEFT JOIN (
  SELECT C.name AS classname,C. id AS classid,C.department,WT.sortposition AS classsortposition,WT.deptid
  FROM classes C
  JOIN web_taxonomy WT ON (WT.classid=C.id AND WT.subclassid=0 AND WT.deptid=C.department)
  WHERE web=1 ORDER BY classsortposition
) AS C ON (C.department=D.deptid);

和解释报告:

+----+-------------+------------+------+--------------------------+------------+---------+-----------------------------+------+----------------------------------------------------+
| id | select_type | table      | type | possible_keys            | key        | key_len | ref                         | rows | Extra                                              |
+----+-------------+------------+------+--------------------------+------------+---------+-----------------------------+------+----------------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL  | NULL                     | NULL       | NULL    | NULL                        |    2 | NULL                                               |
|  1 | PRIMARY     | <derived3> | ALL  | NULL                     | NULL       | NULL    | NULL                        |    2 | Using where; Using join buffer (Block Nested Loop) |
|  3 | DERIVED     | C          | ALL  | PRIMARY,id               | NULL       | NULL    | NULL                        |    1 | Using where; Using temporary; Using filesort       |
|  3 | DERIVED     | WT         | ref  | dept_class,dept_subclass | dept_class | 10      | test.C.department,test.C.id |    1 | Using index condition; Using where                 |
|  2 | DERIVED     | D          | ALL  | PRIMARY,id               | NULL       | NULL    | NULL                        |    1 | Using where; Using temporary; Using filesort       |
|  2 | DERIVED     | WT         | ref  | dept_class,dept_subclass | dept_class | 10      | test.D.id,const             |    1 | Using index condition                              |
+----+-------------+------------+------+--------------------------+------------+---------+-----------------------------+------+----------------------------------------------------+

呸!它为部门和类(即ALL类型列中的)运行表扫描,并为每个子查询创建一个临时表,然后在没有任何索引好处的情况下连接它们(这就是 的含义Using join buffer)。不是一个有趣的优化计划。

一般来说,排序应该是 SQL 查询的最后一部分。不要尝试对子查询结果进行排序以绕过优化器。如果可能,您希望连接由索引辅助,但连接的最佳索引的顺序不一定是您希望返回最终结果的顺序。所以让优化器完成连接的工作,然后对最终结果进行排序。

SELECT D.name AS deptname, D.id AS deptid, WT1.sortposition AS deptsortposition,
  C.name AS classname, C.id AS classid, C.department,
  WT2.sortposition AS classsortposition, WT2.deptid
FROM departments AS D
JOIN web_taxonomy AS WT1 ON (WT1.deptid=D.id AND WT1.classid=0)
LEFT OUTER JOIN web_taxonomy AS WT2 ON (WT2.deptid=D.id AND WT2.subclassid=0)
LEFT OUTER JOIN classes AS C ON (C.id=WT2.classid AND C.department=WT2.deptid)
ORDER BY deptsortposition, classsortposition;

这仍然使用一个临时表和文件排序,但不是两个。它避免了连接缓冲区;每个连接都是索引辅助的。

+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys            | key           | key_len | ref              | rows | Extra                           |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+---------------------------------+
|  1 | SIMPLE      | D     | ALL    | PRIMARY,id               | NULL          | NULL    | NULL             |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | WT1   | ref    | dept_class,dept_subclass | dept_class    | 10      | test.D.id,const  |    1 | Using where; Using index        |
|  1 | SIMPLE      | WT2   | ref    | dept_subclass            | dept_subclass | 10      | test.D.id,const  |    1 | Using where                     |
|  1 | SIMPLE      | C     | eq_ref | PRIMARY,id               | PRIMARY       | 8       | test.WT2.classid |    1 | Using where                     |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+---------------------------------+
于 2013-11-11T16:58:57.277 回答