2

我们有一个庞大的(并且不断增长的)鸟类记录的 MySQL 数据库。目前我们主要有三个表,简化如下:

RECORDS (id, birdid, tripid, gender, age) PRIMARY KEY id
BIRDTRIPS (id, locid, date, starttime, endtime, notes) PRIMARY KEY id
LOCATIONS (id, description, centerlat, centerlng) PRIMARY KEY id

所有 id 都是 INT,日期是 DATE 类型。

为了获得性能,我决定通过将 date 和 locid 复制到 RECORDS 中来进行一些非规范化:

RECORDS (id, birdid, tripid, gender, age, locid, date) PRIMARY KEY id

这样,许多查询将避免昂贵的 BIRDTRIPS 和 LOCATIONS 连接。

MySQL 每个表只有一个聚集索引,并且这始终是主键。我很想
尝试PRIMARY KEY (date, id)使用 RECORDS 来利用聚集索引来更快地对日期列进行范围扫描和对表进行分区。id 仅包含在键中,因为同一日期可能有许多记录。从理论上讲,主键通常在 id 上有点“浪费”,其中非聚集 UNIQUE 索引足以进行查找。

现在我的问题:

你们中有人对这种方法有实际经验吗?有什么我可能忽略的缺点吗?

4

1 回答 1

1

我会回答我自己的问题,以防有人偶然发现。我发现这篇非常不错的博客文章已经测试了这种方法的性能:聚集索引和查询性能

博文中进行的实验得出的结论是:

优点:

  1. 在我的例子中,使用复合主键可以将PRIMARY KEY (date, id)日期范围查询速度提高大约 9 倍。

  2. 随着表的增长,日期范围查询的性能将保持接近恒定,而如果主键仅在“id”上,它将逐渐降低。

缺点:

  1. 使用复合索引,对“id”列的简单查找(例如表上的连接)几乎要慢三倍。

  2. 较大的聚集索引会导致磁盘利用率显着增加。这是因为所有其他索引都指向聚集索引,这意味着大型聚集索引会增加所有其他索引的大小。这可能会导致查询的缓存命中次数减少,因为更少的表可以放入内存。

因此,如果针对表的查询的主要部分是业务关键日期范围查询,并且您的系统可以“承受”查找的惩罚,那么这种方法可能会对您有所帮助。

我自己的结论是,我不敢在生产中这样做。相反,我将对日期列的 YEAR 进行表分区,以防止对日期范围查询进行全表扫描。

希望这将帮助面临类似挑战的人。

于 2014-08-05T12:22:16.743 回答