2014-12-07 161 views
0

所以我有一个查询:MySQL查询太慢?

SELECT EWRporta2_articles.*, xf_thread.*, xf_forum.*, xf_user.*, xf_post.message, 
    IF(NOT ISNULL(xf_user.user_id), xf_user.username, xf_thread.username) AS username 
FROM EWRporta2_articles 
    INNER JOIN xf_thread ON (xf_thread.thread_id = EWRporta2_articles.thread_id) 
    INNER JOIN xf_forum ON (xf_forum.node_id = xf_thread.node_id) 
    INNER JOIN xf_post ON (xf_post.post_id = xf_thread.first_post_id) 
    LEFT JOIN xf_user ON (xf_user.user_id = xf_thread.user_id) 
WHERE EWRporta2_articles.article_date < 1417987751 
    AND xf_thread.discussion_state = 'visible' 
ORDER BY EWRporta2_articles.article_date DESC 
LIMIT 0, 5 

该查询在0.0012秒执行......那好。这个查询所做的是查询文章列表,然后将它们链接到我论坛上的一个主题。

但是,我试图稍微改变查询。虽然上面的查询要求线程存在文章行。我想查找链接到特定文章或存在于特定论坛节点ID中的线索。因此,即使线程中不存在文章行,但如果它具有特定的node_id,它仍会显示出来。这是我对此的查询:

SELECT EWRporta2_articles.*, xf_thread.*, xf_forum.*, xf_user.*, xf_post.message, 
    IF(EWRporta2_articles.article_date IS NULL, xf_thread.post_date, EWRporta2_articles.article_date) AS article_date, 
    IF(NOT ISNULL(xf_user.user_id), xf_user.username, xf_thread.username) AS username 
FROM xf_thread 
    LEFT JOIN EWRporta2_articles ON (EWRporta2_articles.thread_id = xf_thread.thread_id) 
    INNER JOIN xf_forum ON (xf_forum.node_id = xf_thread.node_id) 
    INNER JOIN xf_post ON (xf_post.post_id = xf_thread.first_post_id) 
    LEFT JOIN xf_user ON (xf_user.user_id = xf_thread.user_id) 
WHERE (xf_thread.node_id IN ('66','78') OR EWRporta2_articles.article_date IS NOT NULL) 
    AND IF(EWRporta2_articles.article_date IS NULL, xf_thread.post_date, EWRporta2_articles.article_date) < 1417987751 
    AND xf_thread.discussion_state = 'visible' 
ORDER BY article_date DESC 
LIMIT 0, 5 

此查询的问题是它在0.5683秒内执行。

我能做些什么来提高性能吗?

+2

你没有提供关于你的表的信息,任何存在的索引,也没有提供'EXPLAIN'的结果。没有细节回答这个问题是非常困难的。 – 2014-12-07 21:45:52

+0

除了'explain',''或'可能很难优化。把它写成由'union'连接的两个子查询可能会更好。 – 2014-12-07 21:57:38

+0

只是好奇,是否有一个情况下,user.user_id是NULL,但user.username不是NULL?!?! – Strawberry 2014-12-08 00:17:27

回答

1

首先 - 永远不要做:

​​

使用functon防止任何数据库,以便优化这样一个表达式使用索引。

把它改写成这种形式:

EWRporta2_articles.article_date IS NULL AND xf_thread.post_date < 1417987751 
OR 
EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 

现在使用布尔代数的法律,简化了查询的条件, 特别是在利用法律:Distirbutivity of AND over ORhttp://en.wikipedia.org/wiki/Boolean_algebra
x和(y OR Z)=> X和Y或X和Z



如果您将此法应用于此条件:

WHERE 
(xf_thread.node_id IN ('66','78') OR EWRporta2_articles.article_date IS NOT NULL) 
AND 
(
    EWRporta2_articles.article_date IS NULL AND xf_thread.post_date < 1417987751 
    OR 
    EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 
) 

您将获得:

xf_thread.node_id IN ('66','78') AND EWRporta2_articles.article_date IS NULL AND xf_thread.post_date < 1417987751 
OR 
xf_thread.node_id IN ('66','78') AND EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 
OR 
EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date IS NULL AND xf_thread.post_date < 1417987751 
OR 
EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 

第三个条件是总是假的,所以我们可以跳过它:

EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date IS NULL ... 

第二个和第四一个:

xf_thread.node_id IN ('66','78') AND EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 
OR 
EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 

可以简化为:

EWRporta2_articles.article_date IS NOT NULL AND EWRporta2_articles.article_date < 1417987751 

,它可以进一步简化为:

EWRporta2_articles.article_date < 1417987751 

最后,我们将得到:

WHERE (
    xf_thread.node_id IN ('66','78') 
    AND 
    EWRporta2_articles.article_date IS NULL 
    AND  
    xf_thread.post_date < 1417987751 
    OR 
    EWRporta2_articles.article_date < 1417987751 
) 
    AND xf_thread.discussion_state = 'visible' 

现在划分查询分成两个单独的子查询,那么工会的这样的结果:

SELECT * 
FROM (
    SELECT ...... 
    JOIN ... JOIN ... JOIN ... 
    WHERE 
     xf_thread.node_id IN ('66','78') 
     AND EWRporta2_articles.article_date IS NULL 
     AND xf_thread.post_date < 1417987751 
     AND xf_thread.discussion_state = 'visible' 
    -- ORDER BY article_date DESC 
    LIMIT 0, 5 
) q1 
UNION 
SELECT * 
FROM (
    SELECT ...... 
    JOIN ... JOIN ... JOIN ... 
    WHERE 
     EWRporta2_articles.article_date < 1417987751 
     AND xf_thread.discussion_state = 'visible' 
    ORDER BY article_date DESC 
    LIMIT 0, 5 
) q2 
ORDER BY article_date DESC 
LIMIT 0, 5 

注意,在第一子查询中的条款ORDER BY article_date DESC被跳过 - 由于条件说:AND EWRporta2_articles.article_date IS NULL,那么日期总是空的,我们可以跳过冗余的排序操作,因为这是浪费时间。

+0

一些别名本来不错 – Strawberry 2014-12-08 00:18:16

+0

我得到一个错误使用此代码#1060 - 重复的列名'thread_id'' – 2014-12-08 01:29:22