Mysql 关于从用户处获取最新帖子的可伸缩性的问题有人在关注:两种不同的实现
我有两种不同的实现来检索用户的投票,我想知道哪一种实现适合于更具可伸缩性的数据库。首先我将向您展示这些表,然后是两个实现 投票表Mysql 关于从用户处获取最新帖子的可伸缩性的问题有人在关注:两种不同的实现,mysql,design-patterns,database-design,relational-database,innodb,Mysql,Design Patterns,Database Design,Relational Database,Innodb,我有两种不同的实现来检索用户的投票,我想知道哪一种实现适合于更具可伸缩性的数据库。首先我将向您展示这些表,然后是两个实现 投票表 CREATE TABLE `poll` ( `id` int(1) unsigned NOT NULL AUTO_INCREMENT, `creator_id` int(1) unsigned NOT NULL, `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `question` varcha
CREATE TABLE `poll` (
`id` int(1) unsigned NOT NULL AUTO_INCREMENT,
`creator_id` int(1) unsigned NOT NULL,
`date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`question` varchar(255) NOT NULL,
`num_of_responses` int(1) unsigned DEFAULT NULL,
`num_of_answers` enum('2','3','4','5') NOT NULL,
PRIMARY KEY (`id`),
KEY `creator_id` (`creator_id`),
KEY `date_created` (`date_created`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
repoll表-这两种实现都需要
CREATE TABLE `repoll` (
`repoller_id` int(1) unsigned NOT NULL,
`poll_id` int(1) unsigned NOT NULL,
`date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY `repoller_id` (`repoller_id`),
KEY `poll_id` (`poll_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
下表
CREATE TABLE `following` (
`follower` int(1) unsigned NOT NULL,
`followee` int(1) unsigned NOT NULL,
KEY `follower` (`follower`),
KEY `followee` (`followee`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
用户_提要表-仅在第二次实现时需要
CREATE TABLE `user_feed` (
`user_id` int(1) unsigned NOT NULL,
`poll_id` int(1) unsigned NOT NULL,
`repoller_id` int(1) unsigned DEFAULT NULL,
`date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY `user_id` (`user_id`),
KEY `date_created` (`date_created`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
第一个实现:不需要user_feed表,但是查询在计算上似乎比实现2中的查询要昂贵得多
SELECT P.id, P.creator_id, P.date_created
FROM
following f JOIN
(
SELECT id, creator_id, date_created
FROM poll
UNION ALL
SELECT poll_id, repoller_id, date_created
FROM repoll
) AS P(id, creator_id, date_created)
ON f.followee=P.creator_id
AND f.follower=23
ORDER BY P.date_created DESC
LIMIT 120;
第二个实现:需要user_提要表和repoll表。每次有人发布/重新发布某个内容时,我都会向user_提要表添加一条记录。将为海报的每个追随者添加记录。比如说,我只为user_提要表中的任何特定用户保留120条记录。如果进行了post,并且用户在user_提要表中已经有120条记录,则删除该用户最早的记录并将其添加到repoll表中;新的一个取代了它的位置。如果一个用户请求的记录多于用户提要表中的记录,那么第一个实现将用于检索多余的记录
SELECT uf.poll_id, p.creator_id, uf.repoller_id, uf.date_created
FROM
user_feed uf JOIN poll p
ON uf.poll_id=p.id
AND uf.user_id=23
ORDER BY date_created DESC;
展开原始查询时,该查询似乎正在查找:
- 由23人创建的民意测验
- 由23个
- 由某人创建的民意测验,随后是23次
- 由某人创建的repolls,后跟23
SELECT p.id
, p.creator_id
, p.created_on
, NULL AS repoller_id
FROM poll p
WHERE p.creator_id = 23
ORDER BY p.created_on DESC LIMIT 80
2) 23日前重新发售
SELECT p.id
, p.creator_id
, r.created_on
, r.repoller_id
FROM poll p
JOIN repoll r
ON r.poll_id = p.id
WHERE r.repoller_id = 23
ORDER BY r.created_on DESC LIMIT 80
3) 由某人创建的民意测验,随后是23次
SELECT p.id
, p.creator_id
, p.created_on
, NULL AS repoller_id
FROM poll p
JOIN following f
ON f.followee = p.creator_id
AND f.follower = 23
AND f.follower <> f.followee -- only needed if we don't disallow 23 to follow 23
ORDER BY p.created_on DESC LIMIT 80
SELECT p.id
, r.creator_id
, r.created_on
, r.repoller_id
FROM poll p
JOIN repoll r
ON r.poll_id = p.id
JOIN following f
ON f.followee = r.repoller_id
AND f.follower = 23
AND f.follower <> f.followee -- only needed if we don't disallow 23 to follow 23
ORDER BY r.created_on DESC LIMIT 80
在“following”表中,进行唯一约束,例如
ALTER TABLE `following` ADD PRIMARY KEY (follower, followee)
不是针对此查询,而是针对系统中可能使用的其他查询
CREATE UNIQUE INDEX following_UX1 ON following (followee_id, follower_id)
并在“following”表的singleton列上删除(现在是冗余的)索引
还考虑添加适当的外键约束。
< P>实现1可以改进:SELECT P.id, P.creator_id, P.date_created
FROM following f
JOIN (
( SELECT id, creator_id, date_created
FROM poll
ORDER BY date_created DESC
LIMIT 120
) UNION ALL
( SELECT poll_id, repoller_id, date_created
FROM repoll
ORDER BY date_created DESC
LIMIT 120
)
) AS P ON f.followee=P.creator_id
AND f.follower=23
ORDER BY P.date_created DESC
LIMIT 120;
poll and repoll need: INDEX(creator_id, date_created)
说明:在大多数情况下,看似冗余的顺序依据。。LIMIT..
子句实际上是一种优化。在中,在联合
中选择
,它将最小化联合将创建的临时表中要存储的行数。临时表的行数不超过2*120行;如果表有数百万行,这一点很重要。外部查询还需要子句,以便将子列表混合在一起,并将结果缩减到所需的120
改进索引并允许“覆盖索引”:
说明:我假设follower
和followee
的组合是“唯一的”,因此可以是主键。这样做的性能优势在于,给定跟随器的所有跟随器都位于相邻行中,反之亦然。您最初拥有的要慢得多,因为它必须首先查看索引,然后读取数据以获取这两个字段。我给你的是“覆盖”和“聚集”
你的第二种口味不应该有限制吗
uf
需要索引(用户id、创建日期)
至于你最初的“哪一个”问题。。。我不认为第二个查询做了正确的事情。或
id对性能有致命影响<代码>输入(选择…
对性能有致命影响。请注意,您需要在SELECT
周围设置参数。将中的重写为连接;然后我们可以进一步讨论可伸缩性。还提供了showcreatetable
。正如Rick James所指出的,MySQL优化器可以生成一些可怕的计划,其中包括或条件。通常,我们使用连接操作可以从查询中获得更好的性能。但这一切都取决于可用的索引,以及查询是否能够有效地使用索引,或者MySQL是否因为一个列被包装在一个函数中而不能使用索引。从性能可伸缩性的角度来看,这两个选项我都不喜欢。但乍一看,第二个查询似乎有更好的机会获得合理的访问计划,有合适的索引可用。。。联合操作需要使用文件排序操作来标识和删除重复项。UNION ALL set运算符不执行该操作。为了提高性能,如果不需要识别和删除重复项,请使用UNION ALL。在这两种情况下,要组合的集合的列数和列的数据类型需要匹配。不要用单引号括起标识符。单引号将字符串文字括起来。而内联视图被转换为派生表,这可能会对大型集合造成性能损失。@RickJames-Ok,完全升级了查询。准备好开始讨论实现的可伸缩性了吗?另一种选择是,如果我们在“下表”中为每个创建者id设置了行,使得创建者id跟随自己,并且每个报告者id也跟随自己,那么我们可以消除查询1和2,只使用查询3和4,取消跟随者跟随的限制。耶稣基督。这这太神奇了。你一定是超人或smn。现在就把它通读一遍,我要花一段时间来破译它-新手。但是谢谢你。。。很多我会在处理完之后再给你回复;特别是如果我有任何问题,我们真的需要看看解释,看看预期
CREATE UNIQUE INDEX following_UX1 ON following (followee_id, follower_id)
SELECT P.id, P.creator_id, P.date_created
FROM following f
JOIN (
( SELECT id, creator_id, date_created
FROM poll
ORDER BY date_created DESC
LIMIT 120
) UNION ALL
( SELECT poll_id, repoller_id, date_created
FROM repoll
ORDER BY date_created DESC
LIMIT 120
)
) AS P ON f.followee=P.creator_id
AND f.follower=23
ORDER BY P.date_created DESC
LIMIT 120;
poll and repoll need: INDEX(creator_id, date_created)
CREATE TABLE `following` (
`follower` int unsigned NOT NULL,
`followee` int unsigned NOT NULL,
PRIMARY KEY(`follower`, followee),
INDEX (`followee`, follower)
) ENGINE=InnoDB DEFAULT CHARSET=latin1