views:

411

answers:

3

I have two database tables with the following structure:

actions:

action_id   int(11) primary key
action_name     varchar(255)
action_module   varchar(45)

permissions:

perm_id     int(11) primary key
perm_role   int(11) 
perm_action     int(11)
perm_status     int(11)

Now I have to check whether there is an entry in the permissions table for a given role in the permissions table by inputting the folling data: perm_role, action_name and action_module.

I have prepared two queries to verify the above condition, but I don't have any clue which one is better. Can somebody guide me how to find the best one :

Query 1

SELECT perm_id FROM permissions 
LEFT JOIN actions ON action_id=perm_action 
WHERE perm_role=1 AND action_name='add' AND action_module='employee';

Query 2:

SELECT perm_id FROM permissions, actions 
WHERE perm_role=1 AND perm_action=action_id AND action_name='add' 
AND action_module='employee';

I need to optimize these queries since this has to be executed during every requests made to the server. The development environment is PHP-5.2.10 and MySQL-5.1.35

A: 

Query 1 is better because if u dont use join then sql use it's own hint for the joint and that is some time not good and may it will take time to give you result. and pu the more rows table first in the joint that will work faster and inplace of '=' use like that will work faster. Filter sequence is aslo important.

i sugget another thing is that use actionname and get actionid from action table and after that use id in the search criteria in permission table

KuldipMCA
A: 

I'd go with the first one: the relation between the tables is much clearer in that version. I'm not even sure the second one is correct. As for speed: profile the query or just time the queries.

A side remark on the second query: probably an INNER JOIN is sufficient here.

Martijn
"I'd go with the ***first*** one...I'm not even sure the ***first*** one is correct" - Guessing one of these is a typo - but which one? ;)
butterchicken
You're right. Thanks butterchicken
Martijn
+2  A: 

Your first option with an explicit join between the two tables on explicit fields is the better option to choose for a number of reasons.

The second option is still effectively a join even if you don't use the JOIN keyword as it's an implied join. This means that your database engine will effectively perform it's own join between your table list.

In MySQL, this implied join is a CROSS JOIN which in MySQL is equivalent to an INNER JOIN, however, be aware that a CROSS JOIN is NOT equivalent to an INNER JOIN in "standard" SQL, so whilst your second query may well work if constructed correctly with the correct where filtering, it's ambiguous.

As a result, your second query (with the implied join) can effectively produce a Cartesian product between the two tables (where effectively every row from one table is combined with every row from another table). You'll almost certainly NOT want this and it's one way to destroy the performance of a SQL query, especially if at least one of the tables contains quite a few rows! Even if your filter clauses (i.e. your WHERE clauses) can correctly filter out the rows you don't want to only return the correct result set, it'll be less efficient than explicitly defining your own explicit joins (Even though most database engines will attempt to optimize such implied queries). Your first query uses an explicit LEFT JOIN and so a Cartesian product shouldn't be possible (assuming you are joining on "sensible" fields - from your question it seems the table relationship is "sensible").

Also, be aware that the precedence of simply implying joins between tables by listing tables with a comma separator is lower than actual explicit JOIN statements (at least since MySQL v5.x) This can lead to incorrect query results, especially in the case of join between 3 or more tables where, again, ambiguity in the query expression makes it difficult to determine precedence, and thus the exact same query can produce entirely different results between database versions. See this link for more information.

The best source of information for the various JOIN types in MySQL is the MySQL documentation itself, and the page specifically relating to joins can be found here:

12.2.8.1. JOIN Syntax (MySql v5)

12.2.9.1. JOIN Syntax (MySql v6)

Just for speed, I've quoted the most pertinent sections below:

INNER JOIN and , (comma) are semantically equivalent in the absence of a join condition: both produce a Cartesian product between the specified tables (that is, each and every row in the first table is joined to each and every row in the second table).

However, the precedence of the comma operator is less than of INNER JOIN, CROSS JOIN, LEFT JOIN, and so on. If you mix comma joins with the other join types when there is a join condition, an error of the form Unknown column 'col_name' in 'on clause' may occur.

--

The evaluation of multi-way natural joins differs in a very important way that affects the result of NATURAL or USING joins and that can require query rewriting. Suppose that you have three tables t1(a,b), t2(c,b), and t3(a,c) that each have one row: t1(1,2), t2(10,2), and t3(7,10). Suppose also that you have this NATURAL JOIN on the three tables:

SELECT ... FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;

Previously, the left operand of the second join was considered to be t2, whereas it should be the nested join (t1 NATURAL JOIN t2). As a result, the columns of t3 are checked for common columns only in t2, and, if t3 has common columns with t1, these columns are not used as equi-join columns. Thus, previously, the preceding query was transformed to the following equi-join:

SELECT ... FROM t1, t2, t3 WHERE t1.b = t2.b AND t2.c = t3.c;

That join is missing one more equi-join predicate (t1.a = t3.a). As a result, it produces one row, not the empty result that it should. The correct equivalent query is this:

SELECT ... FROM t1, t2, t3 WHERE t1.b = t2.b AND t2.c = t3.c AND t1.a = t3.a;

If you require the same query result in current versions of MySQL as in older versions, rewrite the natural join as the first equi-join.

--

Previously, the comma operator (,) and JOIN both had the same precedence, so the join expression t1, t2 JOIN t3 was interpreted as ((t1, t2) JOIN t3). Now JOIN has higher precedence, so the expression is interpreted as (t1, (t2 JOIN t3)). This change affects statements that use an ON clause, because that clause can refer only to columns in the operands of the join, and the change in precedence changes interpretation of what those operands are.

Example:

CREATE TABLE t1 (i1 INT, j1 INT); CREATE TABLE t2 (i2 INT, j2 INT); CREATE TABLE t3 (i3 INT, j3 INT); INSERT INTO t1 VALUES(1,1); INSERT INTO t2 VALUES(1,1); INSERT INTO t3 VALUES(1,1); SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);

Previously, the SELECT was legal due to the implicit grouping of t1,t2 as (t1,t2). Now the JOIN takes precedence, so the operands for the ON clause are t2 and t3. Because t1.i1 is not a column in either of the operands, the result is an Unknown column 't1.i1' in 'on clause' error. To allow the join to be processed, group the first two tables explicitly with parentheses so that the operands for the ON clause are (t1,t2) and t3:

SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);

Alternatively, avoid the use of the comma operator and use JOIN instead:

SELECT * FROM t1 JOIN t2 JOIN t3 ON (t1.i1 = t3.i3);

This change also applies to statements that mix the comma operator with INNER JOIN, CROSS JOIN, LEFT JOIN, and RIGHT JOIN, all of which now have higher precedence than the comma operator.

CraigTP
Thanks for this wonderful explanation.
libregeek