A quick check on Wikipedia doesn't mentioned if an "outer join" implies left, right or full when this important bit is omitted.
Practically,
- "outer join" by iself isn't supported. You normally require LEFT, RIGHT or FULL
- "natural" means "join on column with the same names"
This means
- "Natural outer join" won't be recognised
- "Natural full outer join" is "full outer join" with "natural" matching
Indexs/keys don't matter in this case and make no difference.
The result you get is correct for the standard
select *
from
R
full outer join
S ON R.B = S.B
or
select *
from
R
full outer join
S USING (B)
Note: not all RDBMS support all syntax:
- SQL Server doesn't support NATURAL (a good thing)
- MySQL doesn't support FULL OUTER JOIN (can be worked around)
Natural joins are dangerous anyway (SO links)
You write:
Each customer can have multiple sites, but only one should be
displayed in this list.
Yet, your query retrieves all rows. That would be a point to optimize. But you also do not define which site
is to be picked.
Either way, it does not matter much here. Your EXPLAIN
shows only 5026 rows for the site
scan (5018 for the customer
scan). So hardly any customer actually has more than one site. Did you ANALYZE
your tables before running EXPLAIN
?
From the numbers I see in your EXPLAIN
, indexes will give you nothing for this query. Sequential table scans will be the fastest possible way. Half a second is rather slow for 5000 rows, though. Maybe your database needs some general performance tuning?
Maybe the query itself is faster, but "half a second" includes network transfer? EXPLAIN ANALYZE would tell us more.
If this query is your bottleneck, I would suggest you implement a materialized view.
After you provided more information I find that my diagnosis pretty much holds.
The query itself needs 27 ms. Not much of a problem there. "Half a second" was the kind of misunderstanding I had suspected. The slow part is the network transfer (plus ssh encoding / decoding, possibly rendering). You should only retrieve 100 rows, that would solve most of it, even if it means to execute the whole query every time.
If you go the route with a materialized view like I proposed you could add a serial number without gaps to the table plus index on it - by adding a column row_number() OVER (<your sort citeria here>) AS mv_id
.
Then you can query:
SELECT *
FROM materialized_view
WHERE mv_id >= 2700
AND mv_id < 2800;
This will perform very fast. LIMIT
/ OFFSET
cannot compete, that needs to compute the whole table before it can sort and pick 100 rows.
pgAdmin timing
When you execute a query from the query tool, the message pane shows something like:
Total query runtime: 62 ms.
And the status line shows the same time. I quote pgAdmin help about that:
The status line will show how long the last query took to complete. If
a dataset was returned, not only the elapsed time for server execution
is displayed, but also the time to retrieve the data from the server
to the Data Output page.
If you want to see the time on the server you need to use SQL EXPLAIN ANALYZE
or the built in Shift + F7
keyboard shortcut or Query -> Explain analyze
. Then, at the bottom of the explain output you get something like this:
Total runtime: 0.269 ms
Best Answer
Like @Akina says in his comment, "," and CROSS JOIN is equivalent:
This is also known as CARTESIAN PRODUCT. The result will have a cardinality (size) of:
| A, B | = | A | * | B |
We can restrict the result so that it becomes a subset of the CROSS JOIN like:
The corresponding operation becomes
INNER can be left out:
OUTER JOIN is a bit more complicated to explain in terms of sets, but let's start with a LEFT OUTER JOIN:
This means:
I deliberately left out any information regarding columns in the resultset.
is equal to
Finally FULL OUTER JOIN is a UNION between a LEFT and a RIGHT outer JOIN:
is equal to:
To get it completely right we would need to extend the explanation with the columns involved.
I use to think that the "," notation was short and sweet, but after spending years and years of tuning, modifying and extending existing SQL I now prefer the ANSI JOINs over the "," ones. As shown in the comments by ypercubeᵀᴹ fiddle strange things can happen if you have a "," join and the extend it with an ANSI join. I also find it much easier to convince myself that I have gotten the join conditions correct when they are closely located with the join, instead of the WHERE clause:
vs