0

我正在构建一个复杂的多表 MySQL 查询,即使它有效,我想知道我能否让它更简单。

其背后的想法是,使用记录所有站点交互的事件表,选择 10 个最受欢迎的博客文章的 ID、标题和 Slug,并按点击次数降序排列。

SELECT content.id, content.title, content.slug, COUNT(events.id) AS hits 
FROM content, events
WHERE events.created >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
    AND events.page_url REGEXP  '^/posts/[0-9]'
    AND content.id = events.content_id
GROUP BY content.id
ORDER BY hits DESC
LIMIT 10

博客文章 URL 具有以下格式:

/posts/2013-05-16-hello-world

正如我所提到的,它似乎有效,但我确信我可以做这个更清洁。

谢谢,

4

2 回答 2

1

您可以使用left函数,而不是正则表达式:

SELECT content.id, content.title, content.slug, COUNT(events.id) AS hits FROM content JOIN events ON content.id = events.content_id
            WHERE events.created >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
            AND left( events.page_url, 7) = '/posts/'
            GROUP BY content.id
            ORDER BY hits DESC
            LIMIT 10)

但这只是我的想法,没有小提琴,未经测试。评论中提出的 JOIN 建议也很好,并已反映在我的回答中。

于 2013-05-16T00:10:25.683 回答
1

条件开created和条件开page_url都是范围条件。在 SQL 查询中,您只能为每个表的一个范围条件获取索引帮助,因此您必须选择一个或另一个进行索引。

我会在两列(content_id,created)上的事件表上创建一个索引。

ALTER TABLE events ADD KEY (content_id, created);

我假设按创建日期限制比按 page_url 限制更具选择性,因为我假设“/posts/”将匹配大多数事件。

在按创建日期缩小匹配行的范围后,页面 URL 条件将必须由 SQL 层处理,但希望不会太低效。

SQL-89(“逗号样式”)连接语法和 SQL-92 语法之间没有性能差异JOIN。我推荐 SQL-92 语法,因为它更清晰并且支持外连接,但性能不是使用它的理由。SQL 查询优化器支持这两种连接样式。

临时表和文件排序通常对性能来说代价高昂。此查询必然会创建一个临时表并使用文件排序,因为您对不同的列使用 GROUP BY 和 ORDER BY。您只能希望临时表足够小以适合您的tmp_table_size限制(或增加该值)。但是,如果 content.title 或 content.slug 是 BLOB/TEXT 列,那将无济于事,无论如何临时表都将被迫在磁盘上假脱机。

于 2013-05-16T00:38:51.913 回答