I have a generated query from an ORM that selects data from a nested join on a junction table.
When executing it looks like it performs a full table scan on a table with >55 million records resulting in a slow execution time.
My expectation was that it would perform the filtering first then lookup by index for the join.
Here is the query: (additional columns have been removed for brevity)
SELECT
e."SnapshotId"
FROM
"EFACSnapshot" AS e
LEFT JOIN
(
SELECT
e0."SnapshotId"
FROM
"EFACSnapshotVector3" AS e0
INNER JOIN
"Vector3" AS v3
ON e0."Vector3Id" = v3."Vector3Id"
)
AS t
ON e."SnapshotId" = t."SnapshotId"
WHERE
e."ClientId" = 386707
Query Plan
[
{
"Plan": {
"Node Type": "Hash Join",
"Join Type": "Right",
"Startup Cost": 1814295.06,
"Total Cost": 2160533.66,
"Plan Rows": 6020,
"Plan Width": 4,
"Actual Startup Time": 97144.904,
"Actual Total Time": 111542.936,
"Actual Rows": 155,
"Actual Loops": 1,
"Output": [
"e.\"SnapshotId\""
],
"Hash Cond": "(e0.\"SnapshotId\" = e.\"SnapshotId\")",
"Shared Hit Blocks": 2,
"Shared Read Blocks": 358552,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 163599,
"Temp Written Blocks": 163473,
"Plans": [
{
"Node Type": "Hash Join",
"Parent Relationship": "Outer",
"Join Type": "Inner",
"Startup Cost": 1811166.81,
"Total Cost": 2152829.01,
"Plan Rows": 1204320,
"Plan Width": 4,
"Actual Startup Time": 94371.544,
"Actual Total Time": 110790.36,
"Actual Rows": 1204320,
"Actual Loops": 1,
"Output": [
"e0.\"SnapshotId\""
],
"Hash Cond": "(e0.\"Vector3Id\" = v3.\"Vector3Id\")",
"Shared Hit Blocks": 2,
"Shared Read Blocks": 358548,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 163599,
"Temp Written Blocks": 163473,
"Plans": [
{
"Node Type": "Seq Scan",
"Parent Relationship": "Outer",
"Relation Name": "EFACSnapshotVector3",
"Schema": "public",
"Alias": "e0",
"Startup Cost": 0,
"Total Cost": 18553.2,
"Plan Rows": 1204320,
"Plan Width": 8,
"Actual Startup Time": 0.007,
"Actual Total Time": 1936.546,
"Actual Rows": 1204320,
"Actual Loops": 1,
"Output": [
"e0.\"Vector3Id\"",
"e0.\"SnapshotId\""
],
"Shared Hit Blocks": 1,
"Shared Read Blocks": 6509,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
{
"Node Type": "Hash",
"Parent Relationship": "Inner",
"Startup Cost": 904608.36,
"Total Cost": 904608.36,
"Plan Rows": 55256836,
"Plan Width": 4,
"Actual Startup Time": 94369.276,
"Actual Total Time": 94369.276,
"Actual Rows": 55256837,
"Actual Loops": 1,
"Output": [
"v3.\"Vector3Id\""
],
"Hash Buckets": 262144,
"Hash Batches": 64,
"Original Hash Batches": 64,
"Peak Memory Usage": 30422,
"Shared Hit Blocks": 1,
"Shared Read Blocks": 352039,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 159326,
"Plans": [
{
"Node Type": "Seq Scan",
"Parent Relationship": "Outer",
"Relation Name": "Vector3",
"Schema": "public",
"Alias": "v3",
"Startup Cost": 0,
"Total Cost": 904608.36,
"Plan Rows": 55256836,
"Plan Width": 4,
"Actual Startup Time": 0.012,
"Actual Total Time": 50954.107,
"Actual Rows": 55256837,
"Actual Loops": 1,
"Output": [
"v3.\"Vector3Id\""
],
"Shared Hit Blocks": 1,
"Shared Read Blocks": 352039,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
}
]
},
{
"Node Type": "Hash",
"Parent Relationship": "Inner",
"Startup Cost": 3112.53,
"Total Cost": 3112.53,
"Plan Rows": 1257,
"Plan Width": 4,
"Actual Startup Time": 3.052,
"Actual Total Time": 3.052,
"Actual Rows": 31,
"Actual Loops": 1,
"Output": [
"e.\"SnapshotId\""
],
"Hash Buckets": 1024,
"Hash Batches": 1,
"Original Hash Batches": 1,
"Peak Memory Usage": 2,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 4,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0,
"Plans": [
{
"Node Type": "Bitmap Heap Scan",
"Parent Relationship": "Outer",
"Relation Name": "EFACSnapshot",
"Schema": "public",
"Alias": "e",
"Startup Cost": 26.02,
"Total Cost": 3112.53,
"Plan Rows": 1257,
"Plan Width": 4,
"Actual Startup Time": 3.008,
"Actual Total Time": 3.026,
"Actual Rows": 31,
"Actual Loops": 1,
"Output": [
"e.\"SnapshotId\""
],
"Recheck Cond": "(e.\"ClientId\" = 386707)",
"Rows Removed by Index Recheck": 0,
"Shared Hit Blocks": 0,
"Shared Read Blocks": 4,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0,
"Plans": [
{
"Node Type": "Bitmap Index Scan",
"Parent Relationship": "Outer",
"Index Name": "\"IX_EFACSnapshot_ClientId\"",
"Startup Cost": 0,
"Total Cost": 25.71,
"Plan Rows": 1257,
"Plan Width": 0,
"Actual Startup Time": 2.593,
"Actual Total Time": 2.593,
"Actual Rows": 31,
"Actual Loops": 1,
"Index Cond": "(e.\"ClientId\" = 386707)",
"Shared Hit Blocks": 0,
"Shared Read Blocks": 3,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
}
]
}
]
}
]
},
"Triggers": [],
"Total Runtime": 111549.609
}
]
All referenced columns appear to have the correct foreign key and indexing setup.
Could someone explain why a full table scan is being performed and how I can adjust the query to prevent that?
Thanks!



EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)