高效的MySQL表设置和查询

时间:2013-01-29 17:12:20

标签: mysql performance dataset query-optimization

假设我有以下数据库设置(我实际拥有的简化版本):

Table: news_posting (500,000+ entries)
| --------------------------------------------------------------|
| posting_id  | name      | is_active   | released_date | token |
| 1           | posting_1 | 1           | 2013-01-10    | 123   |
| 2           | posting_2 | 1           | 2013-01-11    | 124   |
| 3           | posting_3 | 0           | 2013-01-12    | 125   |
| --------------------------------------------------------------|
PRIMARY posting_id
INDEX sorting ON (is_active, released_date, token)

Table: news_category (500 entries)
| ------------------------------|
| category_id   | name          |
| 1             | category_1    |
| 2             | category_2    |
| 3             | category_3    |
| ------------------------------|
PRIMARY category_id

Table: news_cat_match (1,000,000+ entries)
| ------------------------------|
| category_id   | posting_id    |
| 1             | 1             |
| 2             | 1             |
| 3             | 1             |
| 2             | 2             |
| 3             | 2             |
| 1             | 3             |
| 2             | 3             |
| ------------------------------|
UNIQUE idx (category_id, posting_id)

我的任务如下。我必须得到50个最新的新闻贴子(在一些偏移处),这些贴片是活动的,在今天的日期之前,并且是在请求中指定的20个左右类别中的一个。在我选择要返回的50个新闻帖子之前,我必须按降序按令牌排序相应的新闻帖子。我的查询目前类似于以下内容:

SELECT DISTINCT posting_id
FROM news_posting np
INNER JOIN news_cat_match ncm ON (ncm.posting_id = np.posting_id AND ncm.category_id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20))
WHERE np.is_active = 1
AND np.released_date < '2013-01-28'
ORDER BY np.token DESC LIMIT 50

只有一个指定的category_id,查询不涉及filesort并且速度相当快,因为​​它不必处理重复结果的删除。但是,在具有多个EXPLAIN的上述查询上调用category_id会返回一个表格,表明要完成filesort。而且,我的数据集查询速度非常慢。

有没有办法优化表格设置和/或查询?

1 个答案:

答案 0 :(得分:0)

通过按如下方式重写,我能够使上述查询的运行速度比使用单值类别列表版本更快:

SELECT posting_id
FROM news_posting np
WHERE np.is_active = 1
AND np.released_date < '2013-01-28'
AND EXISTS (
    SELECT ncm.posting_id
    FROM news_cat_match ncm 
    WHERE ncm.posting_id = np.posting_id
    AND ncm.category_id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
    LIMIT 1
)
ORDER BY np.token DESC LIMIT 50

现在我的数据集不到一秒钟。

可悲的是,这比指定的category_id更快。那是因为新闻项的子集比只有一个category_id更大,所以它可以更快地找到结果。

现在我的下一个问题是,对于一个类别只有少量新闻及时传播的情况,是否可以对此进行优化?

以下在我的开发机器上仍然很慢。虽然它在生产服务器上足够快,但我想尽可能优化它。

SELECT DISTINCT posting_id
FROM news_posting np
INNER JOIN news_cat_match ncm ON (ncm.posting_id = np.posting_id AND ncm.category_id = 1)
WHERE np.is_active = 1
AND np.released_date < '2013-01-28'
ORDER BY np.token DESC LIMIT 50

有没有人有任何进一步的建议?