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
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:
—
—