MySQL:使用三个连接优化查询
第一件事:我正在做的工作非常好。我只是想看看是否有改进的余地,我做事情的方式是否符合标准和/或使用良好的实践 这些是有问题的表格:MySQL:使用三个连接优化查询,mysql,database-design,Mysql,Database Design,第一件事:我正在做的工作非常好。我只是想看看是否有改进的余地,我做事情的方式是否符合标准和/或使用良好的实践 这些是有问题的表格: 项目 主题 item\u主题 类似审计的项目 这是我的用例: 有主题,可以包含许多项 每个项目上可以有N个喜欢的项目 对于每个like,一条记录存储在item\u like\u audit表中,以便以后可以查询该记录以进行排名 这就是查询试图实现的目标: 获取过去7天内最受欢迎的某个主题下的所有项目 以下查询或基础架构是否可以以任何方式进行改进(以提高
项目
主题
item\u主题
类似审计的项目
- 有
,可以包含许多主题
李>项
- 每个
上可以有N个喜欢的项目李>项目
- 对于每个like,一条记录存储在
表中,以便以后可以查询该记录以进行排名item\u like\u audit
- 获取过去7天内最受欢迎的某个主题下的所有项目
以下查询或基础架构是否可以以任何方式进行改进(以提高性能或内存) 查询:
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)
);
由于您只返回项目记录,因此可以尝试以下方法以提高性能:
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
- 数据库只需从每个支持表中找到与约束匹配的一行,而不是所有匹配的记录
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
- 数据库只需从每个支持表中找到与约束匹配的一行,而不是所有匹配的记录
item\u-topic(item\u-id,topic\u-id)
是唯一的,我们可以通过去掉DISTINCT
关键字,并将item\u-like\u-audit
的检查重写为一个存在相关子查询,而不是一个联接操作,从而取消“使用文件排序”操作
如果我们有一个独特性的保证
CREATE UNIQUE INDEX item_topic_UX1 ON item_topic (topic_id, item_id);
我们已经保证了主题(slug)
,主题(id)
,项目(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
为了提高相关子查询的性能,我们可以创建一个覆盖索引
我们希望前面创建的唯一索引将用于连接操作,这样也可以提高性能。如果在列中包含deleted\u,我们可以得到一个覆盖索引
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);
如果我们不能保证唯一性,那么我倾向于在DISTINCT
关键字上添加groupbyitem.id
子句
使用EXPLAIN
查看执行计划,并验证是否使用了适当的索引
如果我们不能保证项目主题
中(项目id,主题id)
的唯一性,并且分组依据
操作的“使用文件排序”操作的开销仍然过高
我们可以尝试使用EXISTS检查“匹配主题”条件。(但我不太希望这会更快。)
我们需要为相关子查询的性能提供合适的索引。假设item\u-topic(item\u-id,topic\u-id)
是唯一的,我们可以通过去掉DISTINCT
关键字来取消“使用文件排序”操作,以及将项的检查重写为现有的相关子查询,而不是联接操作
如果我们有一个独特性的保证
CREATE UNIQUE INDEX item_topic_UX1 ON item_topic (topic_id, item_id);
我们已经保证了主题(slug)
,主题(id)
,项目(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
为了提高相关子查询的性能,我们可以创建一个覆盖索引
我们希望前面创建的唯一索引将用于连接操作,这样也可以提高性能。如果在
列中包含deleted\u,我们可以得到一个覆盖索引
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);
如果我们不能保证唯一性,那么我倾向于在DISTINCT
关键字上添加groupbyitem.id
子句
使用EXPLAIN
查看执行计划,并验证是否使用了适当的索引
如果我们不能保证项目主题
中(项目id,主题id)
的唯一性,并且分组依据
操作的“使用文件排序”操作的开销仍然过高
我们可以尝试使用EXISTS检查“匹配主题”条件。(但我不太希望这会更快。)
我们需要为相关子查询的性能提供合适的索引。注意:created_at=DATE(NOW())+INTERVAL-7天
@spencer7593太棒了!谢谢你。由于种子数据中的所有内容的created_at
字段设置为今天,我得到了一个类似的结果集。注意:created_at=DATE(NOW())+INTERVAL-7天
@spencer7593太棒了!谢谢你。我得到了一个类似的结果集,因为对于种子数据中的所有内容,created\u at
字段设置为今天。在这种情况下,我实际上希望所有结果都基于限制和偏移量。因此,如果我有限制10
,我想要10个结果,而不仅仅是一个。结果集本质上是一个“排名靠前的列表”,就其在UI中的显示方式而言