我在扩展应用程序时遇到了一些困难,决定在这里提出一个问题。
考虑一个关系数据库(比如mysql)。假设它允许用户发帖子,这些帖子存储在post表中(有字段:postid, posterid, data, timestamp)因此,当您按近况排序检索所有帖子时,您只需使用posterid = youorder by date获取所有帖子。很简单。
此进程将使用时间戳作为索引,因为它具有最高的基数,因此正确地说是。因此,除了查看索引之外,完成此任务还需要从磁盘获取一行数据令人惊叹的!
但假设自你上次发布以来,其他用户(在系统中)又发布了100万条帖子。然后,为了得到您的最新帖子,数据库会再次将索引钉在时间戳上,这就好像我们不知道此后发生了多少帖子(或者我们至少应该手动估计并设置首选键)?然后我们浪费了一百万行的时间去寻找一行。
另外,来自多个任意用户的一组帖子将是其中一个用例,因此我不能创建像userid_timestamp这样的字段来创建子索引。
我看错了吗?或者,必须从根本上改变应用程序,以允许这样的操作至少在某种程度上有效地发生?

最佳答案

标引
如果您有一个查询:... WHERE posterid = you ORDER BY timestamp [DESC],那么您需要在{posterid,timestamp}上有一个复合索引。
通过对索引前缘(posterid)进行范围扫描来查找给定用户的所有帖子。
查找用户的最早/最新帖子可以在单个索引搜索中完成,该搜索与B树高度成比例,B树高度与log(n)成比例,其中n是索引行数。
要了解原因,请查看Anatomy of an SQL Index
聚类
“普通”b树索引的叶子保存索引行的“指针”(物理地址),而行本身则位于一个称为“表堆”的单独数据结构中。可以通过将行直接存储在b树的叶子(称为clustering)中来消除堆。这有它的优点和缺点,但是如果你有一种主要的查询,通过聚类来消除表堆访问是绝对需要考虑的。
在这种情况下,可以这样创建表:

CREATE TABLE T (
    posterid int,
    `timestamp` DATETIME,
    data VARCHAR(50),
    PRIMARY KEY (posterid, `timestamp`)
);

mysql/innodbclusters all its tables并使用主键作为集群键。我们没有使用代理项键(postid),因为聚集表中的辅助索引可能很昂贵,而且我们已经有了自然键。如果您really need代理项密钥,请考虑将其设为备用密钥,并通过自然密钥建立集群。

10-07 13:26