简体   繁体   中英

How to reduce the number of queries in a normalized database?

Imagine a table for articles. In addition to the main query:

SELECT * From articles WHERE article_id='$id'

We also need several other queries to get

SELECT * FROM users WHERE user_id='$author_id' // Taken from main query

SELECT tags.tag 
FROM tags 
  INNER JOIN tag_map 
    ON tags.tag_id=tag_map.tag_id 
WHERE article_id='$id'

and several more queries for categories, similar articles, etc

Question 1: Is it the best way to perform these queries separately with PHP and handle the given results, or there is way to combine them?

Question 2: In the absence of many-to-many relationships (eg one tag, category, author for every article identified by tag_id, category_id, author_id); What the best (fastest) was to retrieve data from the tables.

If all the relationships are one-many then you could quite easily retrieve all this data in one query such as

SELECT
    [fields required]
FROM
    articles a
    INNER JOIN
        users u ON a.author_id=u.user_id
    INNER JOIN 
        tag_map tm ON tm.article_id=a.article_id
    INNER JOIN
        tags t t.tag_id=tm.tag_id
WHERE
    a.article_id='$id'

This would usually be faster than the three queries separately along as your tables are indexed correctly as MySQL is built to do this! It would save on two round trips to the database and the associated overhead.

You can merge in the user in the first query:

SELECT a.*, u.*
FROM   articles a
JOIN   users u ON u.user_id = a.author_id
WHERE  a.article_id='$id';

You could do the same with the tags, but that would introduce some redundancy in the answer, because there are obviously multiple tags per article. May or may not be beneficial.

In the absence of many-to-many relationships, this would do the job in one fell swoop and would be superior in any case:

SELECT *
FROM   users u
JOIN   articles a ON a.author_id = u.user_id
JOIN   tag t      USING (tag_id)  -- I assume a column articles.tag_id in this case
WHERE  a.article_id = '$id';

You may want to be more selective on which columns to return. If tags ar not guaranteed to exist, make the second JOIN a LEFT JOIN .

You could add an appropriately denormalized view over your normalized tables where each record contains all the data you need. Or you could encapsulate the SQL calls in stored procedures and call these procs from your code, which should aid performance. Prove both out and get the hard figures; always better to make decisions based on evidence rather that ideas. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM