parent
テーブルから単一のレコードを返すクエリを書いています。子がある場合も、このクエリで返したいと思います。これは1対多の関係です。
parent:
-parent_id
-name
child:
-child_id
-name
-parent_id
私の最初の本能は次のクエリを書くことです:
select name, (select count(child_id) from child c where c.parent_id=p.parent_id) children
from parent p
where name like 'some name'
しかし、私は実際にはカウントを気にしないので、これがより効率的な方法があるかどうか疑問に思っていました。子があるかどうかだけです。ポインタはありますか?
Postgresにはブールデータ型があることを忘れないでください。以下は、クエリを表現する最も簡潔な方法です。
select
parent_id,
name,
exists (select from child where parent_id = p.parent_id) as has_children
from parent p;
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=86748ba18ba8c0f31f1b77a74230f67b
集約メソッドと呼ぶ一般的な方法。 注bool_or(child_id IS NOT NULL)
も機能しますが、速くはありませんでした。
_SELECT parent_id, count(*)>1 AS has_children
FROM parent
LEFT OUTER JOIN children
USING (parent_id)
GROUP BY parent_id;
_
LEFT JOIN LATERAL
_制限ありしかし、あなたはこれをLEFT JOIN LATERAL()
のように試してみることもできます。
_SELECT parent_id, has_children
FROM parent AS p
LEFT JOIN LATERAL (
SELECT true
FROM children AS c
WHERE c.parent_id = p.parent_id
FETCH FIRST ROW ONLY
) AS t(has_children)
ON (true);
_
EXISTS
参考までに、EXISTS
で_CROSS JOIN LATERAL
_を使用することもできます(これはどのように計画されていると思います)。 EXISTSメソッドと呼びます。
_SELECT parent_id, has_children
FROM parent AS p
CROSS JOIN LATERAL (
SELECT EXISTS(
SELECT
FROM children AS c
WHERE c.parent_id = p.parent_id
)
) AS t(has_children);
_
これは同じです
_SELECT parent_id, EXISTS(
SELECT
FROM children AS c
WHERE c.parent_id = p.parent_id
) AS has_children
FROM parent AS p;
_
子供1000000人、両親2500人。私たちのシムはそれを成し遂げます。
_CREATE TABLE parent (
parent_id int PRIMARY KEY
);
INSERT INTO parent
SELECT x
FROM generate_series(1,1e4,4) AS gs(x);
CREATE TABLE children (
child_id int PRIMARY KEY,
parent_id int REFERENCES parent
);
INSERT INTO children
SELECT x, 1 + (x::int%1e4)::int/4*4
FROM generate_series(1,1e6) AS gs(x);
VACUUM FULL ANALYZE children;
VACUUM FULL ANALYZE parent;
_
LEFT JOIN LATERAL ( FETCH FIRST ROW ONLY )
:850ミリ秒さて、インデックスを追加しましょう
_CREATE INDEX ON children (parent_id);
ANALYZE children;
_
これで、タイミングプロファイルはまったく異なります、
LEFT JOIN LATERAL ( FETCH FIRST ROW ONLY )
:30msこれは私がSQLサーバーで行う方法です(私はpostgresqlを持っていません-私はそれが似ていると思います)
SELECT p.parent_id,
CASE WHEN EXISTS (SELECT 1 FROM Child c WHERE c.ParentId=p.ParentId)
THEN 'Yes'
ELSE 'No'
END as has_child,
FROM Parent p
--WHERE EXISTS (SELECT 1 FROM Child c WHERE c.ParentId=p.ParentId)