技術共有|派生テーブルの外部参照
作者:Guilhem Bichot
原文:管長龍
LATERALを使用すると、JOINは2番目のテーブル-サブクエリベースの派生テーブル-1番目のテーブルのカラムの値に基づいて定義できるので、1番目のテーブルの各行を再計算できます.標準:
第2のテーブル(派生)において、t 1.colは、最初のテーブルt 1の「横外部参照」である.参照されるテーブルは、派生テーブルの「横」に配置されます(つまり、両方が同じFROM句の一部です).
このLATERAL機能を実装するとき、派生テーブルの非横外部参照をサポートする別の関連機能を追加しました.
階層データの例:
直接および間接的なレポートを受信した人の数は?このプロシージャにはMySQL再帰構文が含まれています
説明:従業員1人あたり:標識量子クエリ(2-12行目)count_を評価of_all_Reports、そのうち: 従業員のすべての直接および間接レポートを再帰的に検索することによってCTE(3-10行目) を構築する. CTEの行数(11行目)を計算し、1行を減算して従業員 を計算しないはカウントを返します.
CTEは共通式(Common Table Expression)を意味し、通常は複雑なクエリーの構築に使用されます.
結果:
CTEの解釈:SELECT emp.idは再帰を開始し、これは私たちが計算したい現在の従業員への参照です.これはidは、その中の1行のemp(CTEの外)から来ている.
[参照](Reference)から[参照カラム](Reference Columns)まで矢印を描くと、CTEから境界に移動し、周囲のスケール量子クエリの境界に移動し、最終的に上部クエリに到達します.これが「横外部参照」ではない理由です.
MySQL 8.0.14までは不可能でした(MySQLはCTEの定義でemp.idが何なのか分かりません).
新しいバージョンMySQLはこの参照を検出しました.それはempでなければならないと結論した.idの各行は、スケール量子クエリとその含むCTEを再計算する.
EXPLAINクエリーの表示:
MySQLは、派生テーブルに対しても「依存」(外部データに依存)であることを認識していることを示しています.CTEのUNIONの内容が「キャッシュ不可」であることも見られ、毎回再計算しなければならない.
振り返るとMySQL 8.0.14から:デフォルトでは、上記の例のクエリに示すように、派生テーブルの定義を解析するときに、MySQLは非横外部参照を受け入れます. LATERALキーワードを追加すると、MySQLも横方向の外部参照を受け入れます.すなわち,派生テーブルを含むFROM句でも検索を行う.
注:レポートカウントの問題には、他の解決策があります.1つの解決策は、再帰CTEを使用して、すべての従業員と各間接マネージャとの間のすべての接続をリストし、この大きな結果を使用して各マネージャを集約することです.効果的ですが、読みにくいです.逆に,階層から個々に小さな集合を生成することを行った.したがって、「階層全体/集約」ではなく、「階層全体/集約/重複の一部」です.
原文:管長龍
LATERALを使用すると、JOINは2番目のテーブル-サブクエリベースの派生テーブル-1番目のテーブルのカラムの値に基づいて定義できるので、1番目のテーブルの各行を再計算できます.標準:
SELECT ... FROM t1, LATERAL (SELECT ... FROM t2
^ WHERE t2.col=t1.col ... ) AS derived;
| |
| |
+---------------------------+
第2のテーブル(派生)において、t 1.colは、最初のテーブルt 1の「横外部参照」である.参照されるテーブルは、派生テーブルの「横」に配置されます(つまり、両方が同じFROM句の一部です).
このLATERAL機能を実装するとき、派生テーブルの非横外部参照をサポートする別の関連機能を追加しました.
階層データの例:
CREATE TABLE employees (
id INT PRIMARY KEY NOT NULL,
name VARCHAR(100) NOT NULL,
manager_id INT NULL,
INDEX (manager_id),
FOREIGN KEY (manager_id) REFERENCES employees (id)
);
INSERT INTO employees VALUES
(333, "Yasmina", NULL), # Yasmina is the CEO (manager_id is NULL)
(198, "John", 333), # John has ID 198 and reports to 333 (Yasmina)
(692, "Tarek", 333),
(29, "Pedro", 198),
(4610, "Sarah", 29),
(72, "Pierre", 29),
(123, "Adil", 692);
直接および間接的なレポートを受信した人の数は?このプロシージャにはMySQL再帰構文が含まれています
SELECT emp.*,
(
WITH RECURSIVE reports AS
(
SELECT emp.id
UNION ALL
SELECT e.id
FROM reports AS rep JOIN employees AS e
ON rep.id = e.manager_id
)
SELECT COUNT(*)-1 FROM reports #
) AS count_of_all_reports
FROM employees AS emp;
説明:従業員1人あたり:
CTEは共通式(Common Table Expression)を意味し、通常は複雑なクエリーの構築に使用されます.
結果:
+------+---------+------------+----------------------+
| id | name | manager_id | count_of_all_reports |
+------+---------+------------+----------------------+
| 29 | Pedro | 198 | 2 |
| 72 | Pierre | 29 | 0 |
| 123 | Adil | 692 | 0 |
| 198 | John | 333 | 3 |
| 333 | Yasmina | NULL | 6 |
| 692 | Tarek | 333 | 1 |
| 4610 | Sarah | 29 | 0 |
+------+---------+------------+----------------------+
7 rows in set (0.02 sec)
CTEの解釈:SELECT emp.idは再帰を開始し、これは私たちが計算したい現在の従業員への参照です.これはidは、その中の1行のemp(CTEの外)から来ている.
[参照](Reference)から[参照カラム](Reference Columns)まで矢印を描くと、CTEから境界に移動し、周囲のスケール量子クエリの境界に移動し、最終的に上部クエリに到達します.これが「横外部参照」ではない理由です.
SELECT emp.*,
(
WITH RECURSIVE reports AS
( +----------------------------------+
| |
SELECT emp.id |
UNION ALL |
SELECT e.id |
FROM reports AS rep JOIN employees AS e |
ON rep.id = e.manager_id |
) | crosses CTE's bounds
SELECT COUNT(*)-1 FROM reports |
) AS count_of_all_reports | crosses scalar subquery's bounds
FROM employees AS emp; |
^ |
| |
+-----------------------------+ reaches to farthest outside
MySQL 8.0.14までは不可能でした(MySQLはCTEの定義でemp.idが何なのか分かりません).
新しいバージョンMySQLはこの参照を検出しました.それはempでなければならないと結論した.idの各行は、スケール量子クエリとその含むCTEを再計算する.
EXPLAINクエリーの表示:
+----+--------------------+------------+------------+------+---------------+------------+---------+--------+------+----------+------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+------------+------------+------+---------------+------------+---------+--------+------+----------+------------------------+
| 1 | PRIMARY | emp | NULL | ALL | NULL | NULL | NULL | NULL | 7 | 100.00 | NULL |
| 2 | DEPENDENT SUBQUERY | | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | NULL |
| 3 | DEPENDENT DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 4 | UNCACHEABLE UNION | rep | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Recursive; Using where |
| 4 | UNCACHEABLE UNION | e | NULL | ref | manager_id | manager_id | 5 | rep.id | 1 | 100.00 | Using index |
+----+--------------------+------------+------------+------+---------------+------------+---------+--------+------+----------+------------------------+
MySQLは、派生テーブルに対しても「依存」(外部データに依存)であることを認識していることを示しています.CTEのUNIONの内容が「キャッシュ不可」であることも見られ、毎回再計算しなければならない.
振り返るとMySQL 8.0.14から:
注:レポートカウントの問題には、他の解決策があります.1つの解決策は、再帰CTEを使用して、すべての従業員と各間接マネージャとの間のすべての接続をリストし、この大きな結果を使用して各マネージャを集約することです.効果的ですが、読みにくいです.逆に,階層から個々に小さな集合を生成することを行った.したがって、「階層全体/集約」ではなく、「階層全体/集約/重複の一部」です.