tags:

views:

246

answers:

10

Hi all,

I have 2 table person and role. I have to all the persons based on role.

select person.* from person inner join role on
person.roleid = role.id Where role.id = @Roleid

or

select person.* from person inner join role on
person.roleid = role.id AND role.id = @Roleid

Which one of the above two solutions is better and Why?

+2  A: 

SQL Server should evaluate those queries identically. Personally, I would use the AND. I like to keep all of the criteria for a joined table in the join itself so that it's all together and easy to find.

Tom H.
Yes, they should evaluate identically, so it's a matter of personal preference, which we can't answer for the OP.
harpo
+12  A: 

The first is better because it's logically coherent. The scoping condition isn't relevant to the join, so making it a part of the join is a kludge, and in this case an unhelpful one.

chaos
Although in at least one case, I discovered that "explain plan" gave me much better results if I put the scope into the join statement.
Paul Tomblin
That's depressing, but unsurprising. :)
chaos
For simple queries like this, it shouldn't make a difference, but for complex queries or for some outer joins, it might. This is because (or so I once heard) the ON clause is resolved before the WHERE clause.
Philip Kelley
A: 

Sqlserver probably has an equivalent of the "explain plan" statement that Oracle, PostgreSQL and MySQL all support in one form or another. It can be very useful in telling you how the query parser and optimizer is going to treat your query.

Paul Tomblin
+2  A: 

Both queries are identical. During query processing, SQL server applies the WHERE filter immediately after applying the join condition filter, so you'll wind up with the same things filtered either way.

mquander
More correct: During query optimization, SQL server chooses the order in which query tasks are accomplished. It might do the filtering task first, or it might do the joining task first. Both queries require both of these tasks.
David B
+1  A: 

I prefer #1, I believe that it expresses the intent of the statement better. That you are joining the two tables based on the roleid & role.id and that you are filtering based on @Roleid

SELECT person.* 
FROM person INNER JOIN role ON person.roleid = role.id 
Where role.id = @Roleid
Nathan Koop
+9  A: 

There is no difference in the relational algebra. Criteria from the where and inner joins like this are interchangeable. I use both depending on the readability and situation.

In this particular case, you could also use:

select person.* from person WHERE person.roleid = @Roleid

The only difference being that it does not require that a row exist in the role table (but I assume you have referential integrity for that) and it will not return multiple rows if roleid is not unique (which it almost certainly is in most scenarios I could foresee).

Cade Roux
A: 

Would there be any performance hit/gain by using this query?

SELECT person.* FROM person,role WHERE person.roleid=role.id AND role.id=@RoleID
Tim
No, that's just an implicit INNER JOIN.
Cade Roux
no, this is a poor syntax, the join standard has been out since 1992, it's time to stop using that obselecent syntax. It is harder to maintain, it doesn't work correctly in SQl Server at all if you use a left join and it is far more likely to result inan accidental cross join.
HLGEM
If I could vote myself down, I would. :-<
Tim
+8  A: 
Gavin Miller
+1 About time someone finally pointed out "Just run them through the profiler and look at the execution plan" :)
Michael Stum
Nice post. It would be better if indexes were present on these tables to give more typical plans.
David B
Unfortunately, many tables don't use indexes. Difference between a database developer and application developer, one uses indexes, the other doesn't think about them.
Dwight T
Maybe I'm not understanding things correctly - The tables in question are doing a clustered index scan, doesn't that mean they're indexed?
Gavin Miller
@Dwight T: No, application developers tend to not know about indexes... @LFSR: YEs that does mean he has indexed, in fact in SQL Server 2005 this USUALLY means they're primary keys (i haven't seen a clustered index on anything, but i could and probably am wrong).
DForck42
A: 

I'd go with the first one, but remember when done testing the code you should explicitly select each table, instead of doing select *

DForck42
A: 

As you are not fetching columns from role you'd better not include it in the FROM clause at all. Use this:

SELECT *
FROM   person
WHERE  person.roleid IN (SELECT id FROM role WHERE id = @Roleid)

This way the optimizer sees only one table in the FROM clause and can quickly figure out the cardinality of the resultset (that is the number of rows in the resultset is <= the number of rows in table person).

When you throw two tables with a JOIN the optimizer has to look in the ON clause to figure out if these tables are equi-joined and whether unique indexes exist on the joined columns. If the predicate in the ON clause is complicated one (multiple ANDs and ORs) or simply wrong (sometimes very wrong) the optimizer might choose sub-optimal join strategy.

Obviously this particular sample is very contrived, because you can filter persons by roleid = @Roleid directly (no join or sub-query) but the considerations above are valid if you had to filter on other columns in role (@Rolename for instance).

wqw