首先是第一件事:我正在做的事情非常好。我只是看看是否有任何改进的空间,如果我做的事情是标准的和/或使用良好的做法。
这些是有问题的表格:
item
topic
item_topic
item_like_audit
。这是我的用例:
topic
个,可以包含多个item
。 item
都可以包含N个喜欢的内容。 item_like_audit
表中,以便稍后可以查询以进行排名。这是查询尝试实现的目的:
可以以任何方式改进以下查询或底层架构(性能或内存增益)吗?
查询:
SELECT DISTINCT item.* FROM item
/* Match items under this specific topic */
JOIN topic
ON topic.slug = ?
AND topic.deleted_at IS NULL
JOIN item_topic
ON item_topic.item_id = item.id
AND item_topic.topic_id = topic.id
AND item_topic.deleted_at IS NULL
/* Match items that have had "like" activity in the past 7 days */
JOIN item_like_audit
ON item_like_audit.item_id = item.id
AND item_like_audit.created_at <= (CURRENT_DATE + INTERVAL 7 DAY)
WHERE item.deleted_at IS NULL
/* Order by highest like count to lowest */
ORDER BY item.like_count DESC
/* Pagination */
LIMIT ? OFFSET ?
架构:
CREATE TABLE item (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL UNIQUE,
tagline VARCHAR(255) NOT NULL,
description VARCHAR(1000) NOT NULL,
price FLOAT NOT NULL,
like_count INT(10) NOT NULL DEFAULT 0,
images VARCHAR(1000) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE item_like_audit (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
item_id INT(10) UNSIGNED NOT NULL,
user_id INT(10) UNSIGNED NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY `item_like_audit_created_at_index` (`created_at`)
);
CREATE TABLE topic (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE item_topic (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
item_id INT(10) NOT NULL,
topic_id INT(10) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id)
);
答案 0 :(得分:1)
由于您只返回项目记录,因此您可以尝试这样做以提高性能:
select Item.*
from Item
where Item.deleted_at is null
and exists (select 1 from item_topic
where item_topic.item_id = item.id
and itme_topic.deleted_at is null
and exists (select 1 from topic
where topic.id = item_topic.item_id
and topic.deleted_at is null
and topic.slug = ?))
and exists (select 1 from item_like_audit
where item_like_audit.item_id = item.id
and item_liek_audit.created_at >= (current_date - interval 7 day))
order by Item.like_count desc
这可以提高性能,因为:
DISTINCT
运营商答案 1 :(得分:1)
假设item_topic(item_id,topic_id)
是唯一的,我们可以取消使用&#34;使用filesort&#34;通过删除DISTINCT
关键字并将item_like_audit
的检查重写为EXISTS相关子查询而不是JOIN操作来进行操作。
如果我们有
,我们可以保证唯一性 CREATE UNIQUE INDEX item_topic_UX1 ON item_topic (topic_id, item_id);
我们已经保证topic(slug)
,topic(id)
,item(id)
,......的独特性
SELECT item.*
FROM item
/* Match items under this specific topic */
JOIN item_topic
ON item_topic.item_id = item.id
AND item_topic.deleted_at IS NULL
JOIN topic
ON topic.id = item_topic.topic_id
AND topic.slug = ?
AND topic.deleted_at IS NULL
WHERE item.deleted_at IS NULL
/* Match items that have had "like" activity in the past 7 days */
AND EXISTS ( SELECT 1
FROM item_like_audit
WHERE item_like_audit.item_id = item.id
AND item_like_audit.created_at >= DATE(NOW()) + INTERVAL -7 DAY
)
/* Order by highest like count to lowest */
ORDER BY item.like_count DESC
为了提高相关子查询的性能,我们可以创建覆盖索引
CREATE INDEX item_like_audit_IX1 ON item_like_audit (item_id, created_at)
我们希望我们之前创建的唯一索引将用于连接操作,因此这也应该提高性能。如果我们包含deleted_at
列
CREATE INDEX item_topic_IX2 ON item_topic (topic_id, item_id, deleted_at)
对于我们之前创建的唯一索引而言,这是多余的,如果我们仍然想要保证唯一性,请翻转列的顺序...
DROP INDEX item_topic_UX1 ON item_topic ;
CREATE UNIQUE INDEX item_topic_UX1 ON item_topic (item_id,topic_id);
如果我们不保证唯一性,那么我建议在GROUP BY item.id
关键字上添加DISTINCT
条款。
使用EXPLAIN
查看执行计划,并验证是否正在使用适当的索引。
如果我们无法保证来自(item_id,topic_id)
的{{1}}的唯一性,以及&#34;使用filesort&#34; item_topic
操作的操作仍然太高,
我们可以尝试检查&#34;匹配主题&#34;条件使用EXISTS。 (但我并不希望这会更快。)
GROUP BY
我们需要有适当的索引来执行相关子查询。