我正构建一个复杂的多表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
博客帖子网址具有以下格式:
/posts/2013-05-16-hello-world
正如我所提到的那样似乎有用,但我确信我可以做得更干净。
谢谢,
答案 0 :(得分: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)
但是,这只是我的头脑,没有fiddle,未经测试。在评论中提出的JOIN建议也很好,并且反映在我的回答中。
答案 1 :(得分:1)
created
上的条件和page_url
上的条件都是范围条件。在SQL查询中,每个表只能获得一个范围条件的索引辅助,因此您必须选择一个或另一个来进行索引。
我会在事件表上通过两列(content_id,created)创建一个索引。
ALTER TABLE events ADD KEY (content_id, created);
我假设按创建日期限制比通过page_url限制更具选择性,因为我假设“/ posts /”将匹配大多数事件。
在按创建日期缩小匹配行之后,必须由SQL层处理page-url条件,但希望这不会太低效。
SQL-89(“逗号样式”)连接语法和SQL-92 JOIN
语法之间没有性能差异。我建议使用SQL-92语法,因为它更清晰,并且它支持外连接,但 performance 不是使用它的理由。 SQL查询优化器支持两种连接样式。
临时表和文件排序通常代价高昂。此查询绑定创建临时表并使用filesort,因为您对不同的列使用GROUP BY和ORDER BY。您只能希望临时表足够小以适应tmp_table_size
限制(或增加该值)。但是如果content.title或content.slug是BLOB / TEXT列,那将无助于临时表,无论如何都会强制在磁盘上假脱机临时表。