<div dir="ltr">Hello,<div><br></div><div>I have a query plan optimization question. It is formatted nicely on </div><div><br></div><div><a href="http://stackoverflow.com/questions/28856452/postgres-not-using-gist-index-in-lateral-join">http://stackoverflow.com/questions/28856452/postgres-not-using-gist-index-in-lateral-join</a><br></div><div><br></div><div>But here is a copy for the archive:</div><br>Here is the setup:<div><br><div>CREATE EXTENSION postgis;</div><div>DROP TABLE IF EXISTS A;</div><div>DROP TABLE IF EXISTS B; </div><div>CREATE TABLE A(shape Geometry, id INT); </div><div>CREATE TABLE B(shape Geometry, id INT, kind INT); </div><div>CREATE INDEX ON A USING GIST (shape); </div><div>CREATE INDEX ON B USING GIST (shape);<br><br>I am running the following commands:</div><div><br><div>ANALYZE A; </div><div>ANALYZE B;</div><div><br></div><div>-- for each row in A, select exactly one row in B (if there is one)</div><div>-- such that B contains <span style="font-size:13.1999998092651px">geometry of A</span></div><div>EXPLAIN
SELECT * FROM (SELECT A.id as aid, (SELECT B.id FROM B WHERE
ST_Contains(B.shape, A.shape)
AND B.kind != 1 LIMIT 1) as bid FROM A) AS TMP;<br><br>which gives me {
"Plan": {
"Node Type": "Seq Scan",
"Relation Name": "A",
"Startup Cost": 0.00,
"Total Cost": 2606592.33,
"Plan Rows": 549745,
"Plan Width": 1646,
"Plans": [
{
"Node Type": "Limit",
"Parent Relationship": "SubPlan",
"Subplan Name": "SubPlan 1",
"Startup Cost": 0.00,
"Total Cost": 4.68,
"Plan Rows": 1,
"Plan Width": 8,
"Plans": [
{
"Node Type": "Seq Scan",
"Parent Relationship": "Outer",
"Relation Name": "B",
"Startup Cost": 0.00,
"Total Cost": 4.68,
"Plan Rows": 1,
"Plan Width": 8,
"Filter": "((shape && A.shape) AND _st_contains(shape, A.shape))"
}
]
}
]
}
}<br><br><br>Note that there is a sequential scan inside the lateral join, however there is clearly an index available. However after setting<br><br>set enable_seqscan=false;<br><br>the index is being used. This actually affects runtime significantly (around 3 times faster) and seems that postgres should figure things like that automatically. {
"Plan": {
"Node Type": "Seq Scan",
"Relation Name": "A",
"Startup Cost": 10000000000.00,
"Total Cost": 10004716493.85,
"Plan Rows": 549450,
"Plan Width": 1677,
"Plans": [
{
"Node Type": "Limit",
"Parent Relationship": "SubPlan",
"Subplan Name": "SubPlan 1",
"Startup Cost": 0.00,
"Total Cost": 8.52,
"Plan Rows": 1,
"Plan Width": 8,
"Plans": [
{
"Node Type": "Index Scan",
"Parent Relationship": "Outer",
"Scan Direction": "NoMovement",
"Index Name": "B_shape_idx",
"Relation Name": "B",
"Startup Cost": 0.00,
"Total Cost": 8.52,
"Plan Rows": 1,
"Plan Width": 8,
"Index Cond": "(shape && A.shape)",
"Filter": "_st_contains(shape, A.shape)"
}
]
}
]
}
}<br><br>Is there any way to tell postgres to use index in a less hacky way? Possibly by rewriting the query? From what I understand the use of set enable_... is not recommended in production.<br><br>When you actually run the commands above it will give</div><div><br></div><div>{
"Plan": {
"Node Type": "Seq Scan",
"Relation Name": "a",
"Alias": "a",
"Startup Cost": 0.00,
"Total Cost": 10372.75,
"Plan Rows": 1230,
"Plan Width": 36,
"Plans": [
{
"Node Type": "Limit",
"Parent Relationship": "SubPlan",
"Subplan Name": "SubPlan 1",
"Startup Cost": 0.14,
"Total Cost": 8.41,
"Plan Rows": 1,
"Plan Width": 4,
"Plans": [
{
"Node Type": "Index Scan",
"Parent Relationship": "Outer",
"Scan Direction": "NoMovement",
"Index Name": "b_shape_idx",
"Relation Name": "b",
"Alias": "b",
"Startup Cost": 0.14,
"Total Cost": 8.41,
"Plan Rows": 1,
"Plan Width": 4,
"Index Cond": "(shape && a.shape)",
"Filter": "((kind <> 1) AND _st_contains(shape, a.shape))"
}
]
}
]
}
}<br><br>Unfortunately I cannot provide data to reproduce the query plan results.</div></div></div><div><br></div><div>Thanks,</div><div>Igor</div></div>