所以我有一个问题:
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秒内执行。
我可以做些什么来提高性能吗?
答案 0 :(得分:1)
首先 - 永远不要那样做:
AND IF(EWRporta2_articles.article_date IS NULL, xf_thread.post_date
, EWRporta2_articles.article_date) < 1417987751
使用功能可以防止任何数据库使用索引来优化像这样的表达式
将其重写为以下形式:
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 OR
:http://en.wikipedia.org/wiki/Boolean_algebra
X AND(Y OR Z)=&gt; 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
,那么日期总是为NULL,我们可以跳过冗余排序操作,因为它是浪费时间。