sql query joins multiple tables - too slow - sql

I am currently trying to join a few tables together (maybe join 2 additional more if possible) but with how my query is written right now, I cant even see the results with 3 tables
select t1.x,
t1.y,
t1.z,
t4.a,
t4.b,
t4.c,
t4.d
from t1
left join t2 on t1.id=t2.id
left join t3 on t2.id=t3.id
left join t4 on t1.id2=t4.id
where t1.date between 'x' and'x'
and t1.city not in ('x')
and t3.column = x;
Is there a way to optimize this code to run faster and perhaps make it able to add more tables to it?
Thank you in advance!

Your query has some logic issues that might help with the speed.
t2 is joined to t1 when they have the same id value.
t3 is then pulled in, if and only if, there was a row in t2 and it has the same value as t1 and t2.
Finally, in your where clause, the t3.column has to be x else it's filtered.
This means a row in t3 has to exist. Every t1 record that doesn't have a t2 record and a t3 record will be filtered out with that where. Thus you don't need a left join, you need an INNER join.
select t1.x,
t1.y,
t1.z,
t4.a,
t4.b,
t4.c,
t4.d
from t1
inner join t2 on t1.id=t2.id
inner join t3 on t2.id=t3.id
left join t4 on t1.id2=t4.id
where t1.date between 'x' and'x'
and t1.city not in ('x')
and t3.column = x;
In some DBMS you can move the t3.column clause to the join command which can help filter out the rows earlier in the plan.
select t1.x,
t1.y,
t1.z,
t4.a,
t4.b,
t4.c,
t4.d
from t1
inner join t2 on t1.id=t2.id
inner join t3 on t2.id=t3.id and t3.column = x
left join t4 on t1.id2=t4.id
where t1.date between 'x' and'x'
and t1.city not in ('x');
My final advise is to take a close look at t2 to see if you really need it. Ask yourself, is there a reason a row has to exist in t2 in order for me to get the right results? ... because if t1.id = t2.id then t1.id = t3.id and you can eliminate the t2 table completely.

Related

SQL Filtering when joining

bit of a novice question, I am running a query and left joining and wanted to know whether there was a difference when you specify a filter in terms of performance, in e.g below, top I filter straight after first join and below I do all joins and then filter:
Select t1.*,t2.* from t1 t1
left join t2 t2
on t1.key = t2.key
and t1.date < today
left join t3 t3
on t2.key2 = t3.key
vs
Select t1.*,t2.* from t1 t1
left join t2 t2
on t1.key = t2.key
left join t3 t3
on t2.key2 = t3.key
and t1.date < today
Learn what LEFT JOIN ON returns: INNER JOIN ON rows UNION ALL unmatched left table rows extended by NULLs. Always know what INNER JOIN you want as part of an OUTER JOIN.
In general your queries have different inner join & null-extended rows for the 1st left joins & then further differences due to more joining. Unless certain constraints hold, the 2 queries return different functions of their inputs. So comparing their performance seems moot.

Tables join using mapping table

I have 3 tables:
table1: col1(id), col2(segment), col3(sector), col4(year)
mapping table2:
col1(segment1) => values are the same as from table1.col2,
col2(segmnet2) =>values are the same as from table3.col2
table3: col1(id), col2(segment), col3(sector), col4(year)
Now, Im doing FULL OUTER JOIN:
select t1.id, t3.id
from table1 t1
full outer join table3 t3 on
t1.year = t3.year and....
But I also need to join by COL2 - SEGMENT, with using mapping table.
How to do correctly do it?
If I understood you correctly, you just need to add another full outer join:
select t1.id, t3.id
from table1 t1
full outer join mapping t2 on( t1.col2= t2.col1)
full outer join table3 t3 on(t1.year = t3.year and t2.col2 = t3.col2
Just to make sure - a full outer join keeps all the records from both tables being joined, no matter if there is a match or not! I've added another full outer join but change it to the kind of join you need if it isn't full.

Multiple joins in a sql query - which is best option

I want to use a sql query with multiple joins similar to the example below.
SELECT t1.column1, t1.column2, t1.column3
FROM
table1 t1
LEFT JOIN table2 t2 ON (t1.id1 = t2.id)
LEFT JOIN table3 t3 ON (t1.id1 = t3.id)
JOIN table4 t4 ON t1.id2 = t4.id
WHERE
...
Would this give different results than the following query:
SELECT t1.column1, t1.column2, t1.column3
FROM
table1 t1
LEFT JOIN table2 t2 ON (t1.id1 = t2.id)
LEFT JOIN table3 t3 ON (t2.id = t3.id)
JOIN table4 t4 ON t1.id2 = t4.id
WHERE
...
If they are both 'correct' is the second more efficient than the first?
Thanks
The queries are different, so this isn't a performance issue. The difference are these lines:
LEFT JOIN table3 t3 ON (t1.id1 = t3.id)
and
LEFT JOIN table3 t3 ON (t2.id1 = t3.id)
For the first, t3.id needs to only match t1.id. For the second, it needs to match t2.id1, which in turn must also match t1.id. In other words, the second version requires that the id be in both t1 and t2.
This is because of the LEFT JOIN. The queries would be equivalent if they used INNER JOIN.
The second one is more efficient because it will always return the same or less amount of data.
In the first query you are asking for all the records that are both in table1 and table4 + records from table2 if they exists in table1 + records from the table3 if they exists in table1.
In the second query you are asking for all the records that are both in table1 and table4 + records from table2 if they exists in table1 + records from the table3 if they exists BOTH in in table1 and in table2

join with the on supplied later

I have a query in the following format
select
*
from
Table1 t1
inner join Table2 t2
inner join Table3 t3 on t2.ID = t3.ID
on t3.ID = t1.ID
What I do know:
Not providing the last on condition results in an error.
Additionally changing the first join condition from on t2.ID = t3.ID to on t1.ID = t2.ID results in an error that t1.ID could not be bound.
Obviously the above examples are arbitrary and may not actually produce a practically useful result. However, an explanation of what providing the on later is actually doing would be great.
Thanks
EDIT
I'm not trying to change the question to something that works but to understand what MSSQL is doing when I provide it.
You can use the format you specified (presuming the correct table aliases), if you use parenthesis.
Select ... -- never use Select *
From (Table1 As T1
Join Table2 As T2
On T2.ID = T1.ID)
Join Table3 As T3
On T3.ID = T1.ID
However, with equi-joins (inner joins) it really makes no difference and it is easier to read if you do not use parenthesis. However, this format is very useful with outer joins. Take the following two examples:
Example 1
Select ...
From Table1 As T1
Left Join Table2 As T2
On T2.T1_ID = T1.ID
Join Table3 As T3
On T3.T2_ID = T2.ID
Example 2
Select ...
From Table1 As T1
Left Join (Table2 As T2
Join Table3 As T3
On T3.T2_ID = T2.ID)
On T2.T1_ID = T1.ID
Suppose in this situation, that T3.T2_ID is a non-nullable foreign key to Table2. In Example1, the Inner Join to Table3 will effectively filter out rows that would have been null because the given T2.T2_ID does not exist in Table1. However, in the second example, the join between Table2 and Table3 is done before the Left Join to Table1 is processed. Thus, we'll get the same rows from Table1 and Table2 as:
Example 3
Select ...
From Table1 As T1
Left Join Table2 As T2
On T2.T1_ID = T1.ID
Assuming you meant t1 rather than t, then your query:
select
*
from
Table1 t1
inner join Table2 t2
inner join Table3 t3 on t2.ID = t3.ID
on t3.ID = t1.ID
...can be made rather more clear by the addition of the brackets it doesn't really need:
select
*
from
Table1 t1
inner join
(Table2 t2 inner join Table3 t3 on t2.ID = t3.ID) on t3.ID = t1.ID
Effectively, you're explicitly saying "join t2 to t3, then join t1 to that."
Does that help?
First off--you don't define what t is
Table1 is aliased t1
Table2 is aliased t2
Table3 is aliased t3
But there is no plain t.
Second, you are not doing a join of t1 to t2, but of t1 to t3 and then t3 to t2. That will work. If there is a relation between t1 and t2 (t1.ID=t2.ID) then that "on" statement should directly follow the inner join statement for t2:
select
*
from
Table1 t1
inner join Table3 t3 on t1.ID = t3.ID
inner join Table2 t2 on t3.ID = t2.ID
UPDATE (based on your update)
are t1.ID, t2.ID, and t3.ID all the same data type?

SQL - Difference between these Joins?

I should probably know this by now, but what, if any is the difference between the two statements below?
The nested join:
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
ON t2.table2_ID = t1.table1_ID
The more traditional join:
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
Well, it's the order of operations..
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
ON t2.table2_ID = t1.table1_ID
could be rewritten as:
SELECT
t1.*
FROM
table1 t1 -- inner join t1
INNER JOIN
(table2 t2 LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID) -- with this
ON t2.table2_ID = t1.table1_ID -- on this condition
So basically, first you LEFT JOIN t2 with t3, based on the join condition: table3_ID = table2_ID, then you INNER JOIN t1 with t2 on table2_ID = table1_ID.
In your second example you first INNER JOIN t1 with t2, and then LEFT JOIN the resulting inner join with table t3 on the condition table2_ID = table1_ID.
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
could be rewritten as:
SELECT
t1.*
FROM
(table1 t1 INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID) -- first inner join
LEFT JOIN -- then left join
table3 t3 ON t3.table3_ID = t2.table2_ID -- the result with this
EDIT
I apologize. My first remark was wrong. The two queries will produce the same results but there may be a difference in performance as the first query may perform slower than the second query in some instances ( when table 1 contains only a subset of the elements in table 2) as the LEFT JOIN will be executed first - and only then intersected with table1. As opposed to the second query which allows the query optimizer to do it's job.
For your specific example, I don't think there should be any difference in the query plans generated, but there's definitely a difference in readability. Your 2nd example is MUCH easier to follow.
If you were to reverse the types of joins in the example, you could end up with much different results.
SELECT t1.*
FROM table1 t1
LEFT JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
-- may not produce the same results as...
SELECT t1.*
FROM table1 t1
LEFT JOIN table2 t2
INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
ON t2.table2_ID = t1.table1_ID
Based on the fact that order of the joins DOES matter in many cases - careful thought should go into how you're writing your join syntax. If you find that the 2nd example is what you're really trying to accomplish, i'd consider rewriting the query so that you can put more emphasis on the order of your joins...
SELECT t1.*
FROM table2 t2
INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
RIGHT JOIN table1 t1 ON t2.table2_ID = t1.table1_ID
The best way to see what is different in these two queries is to compare the Query Plan for both these queries.
There is no difference in the result sets for these IF there are always rows in table3 for a given row in table2.
I tried it on my database and the difference in the query plans was that
1. For the first query, the optimizer chose to do the join on table2 and table 3 first.
2. For the second query, the optimizer chose to join table1 and table2 first.
You should see no difference at all between the two queries, provided your DBMS' optimizer is up to scratch. That, however, even for big-iron, high-cost platforms, is not an assumption I'd be confident in making, so I'd be fairly unsurprised to discover that query plans (and consequently execution times) varied.