【发布时间】:2013-07-27 18:53:51
【问题描述】:
我有一个博客,通过在表 (views) 中插入访问者的 IP、帖子 ID(我在这些字段上获得主键)和时间戳,我可以跟踪谁查看了哪些帖子以及何时查看。
然后使用此表显示我的每个类别的前 5 个帖子(其中有 4 个)在最后一天/一周/一个月/一年和所有时间。所以,总共执行了 20 个查询,每个查询都需要 0.2 到 0.7 秒之间……我的页面加载需要 7 秒多一点,这太糟糕了。
这里有一些关于我的数据库结构的有用信息:
+---------------------+ +----------------------+
| posts (82 rows) | | views (50k rows) |
+=====================+ +======================+
| id (primary) | | ip (primary) |
+---------------------+ +----------------------+
| type | | article_id (primary) |
+---------------------+ +----------------------+
| thumbnail | | date (index) |
+---------------------+ +----------------------+
| title (index) |
+---------------------+
| url |
+---------------------+
| description (index) |
+---------------------+
| content |
+---------------------+
| date |
+---------------------+
| lastmod |
+---------------------+
| sources |
+---------------------+
| tags |
+---------------------+
| published |
+---------------------+
| ... |
+---------------------+
... 代表我的帖子英文版的附加字段(url_en、title_en、description_en、tags_en 和 content_en)。
这是我的一个巨大的查询(它们都基本相同):
SELECT p.title, p.id, p.url, tmp.cnt AS views
FROM posts AS p
LEFT JOIN (SELECT COUNT(*) AS cnt, article_id -- 0.34s
FROM views
WHERE article_id IN (SELECT id
FROM posts
WHERE id <> 12 AND type = 'Tutoriel') AND
date BETWEEN 01-01-2013 AND NOW() -- the 01-01-2013 is normally a variable but for testing purposes I've replaced it with a fixed date here
GROUP BY article_id
ORDER BY cnt DESC LIMIT 5) AS tmp
ON p.id = tmp.article_id
WHERE p.id IN (SELECT article_id
FROM (SELECT COUNT(*) AS cnt, article_id -- 0.34s
FROM views
WHERE article_id IN (SELECT id
FROM posts
WHERE id <> 12 AND type = 'Tutoriel')
AND date BETWEEN 01-01-2013 AND NOW()
GROUP BY article_id
ORDER BY cnt DESC LIMIT 5) AS tmp2
)
ORDER BY views DESC
我发现BETWEEN 子句大部分时间都在使用,因为我对所有帖子的所有时间统计信息都进行了完全相同的查询(因此,不依赖于类别或日期)并且只需要0.03 秒执行。
我已经以所有可能的方式查看了这个查询,但找不到更简单、更优化的方式来编写它......但是,我觉得必须有一种方式。也许我只是在这里遗漏了一些明显的东西。
让我烦恼的一件事是我的重复子查询。我没有找到任何其他方法来获取我的帖子数据和相关视图的数量。
我的想法可能是当用户单击该时间段的选项卡(这是一个选项卡式视图)时,为每个时间段执行 AJAX 请求。但是,这并不能真正解决问题,只是感觉像是一种肮脏的解决方法。
我可以通过以下方式之一对我的posts 表进行分区:
- 一张表用于法语版,另一张用于英文版
- 一张表用于常用字段(
title、description、url),另一张用于其余字段 - 以上组合
如果我没记错的话,这可能会加快一点。
有人可以给我一些建议吗?顺便说一句,谢谢你一直陪我到这里:)
【问题讨论】:
-
您没有告诉我们有关索引或数据量的任何信息。由于这是一个非常复杂的问题,您可能需要创建一个SQL Fiddle
-
抱歉,马上编辑。
-
对,忘记在我的查询中编辑名称。这些确实是同一张桌子。刚刚编辑。
-
添加索引以键入会有所帮助。
标签: mysql sql performance optimization subquery