繁体   English   中英

MySQL查询太慢?

[英]MySQL query too slow?

所以我有一个查询:

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秒内执行。

我有什么办法可以改善此处的效果?

首先-永远不要这样做:

AND IF(EWRporta2_articles.article_date IS NULL, xf_thread.post_date
           , EWRporta2_articles.article_date) < 1417987751

使用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 AND(Y OR Z)=> X AND Y OR X AND 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

请注意,在第一AND EWRporta2_articles.article_date IS NULL查询中,由于条件为: AND EWRporta2_articles.article_date IS NULL ,所以跳过了ORDER BY article_date DESC子句,因此日期始终为NULL,并且我们可以跳过多余的排序操作,因为这浪费时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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