use*_*596 7 mysql innodb index primary-key clustered-primary-key
我和 Rick James 就这个问题进行了很长时间的讨论,我们提出了用复合键替换自动增量 pk 的想法,其中 int 限制接近 20 亿。我的表将在几个月内轻松达到此限制,因为我们每月捕获近几亿数据。下面是我的桌子的样子。关键表是gdata
所以我使用 3 个字段组合主表PRIMARY KEY (alarmTypeID,vehicleID,gDateTime)
。然后我有另一个表称为警报表。两者之间的联系是一对多的。这意味着其中的一个数据gdata
可以有零个或多个alarms
与之相关。它们之间的链接是vehicleID
和gDateTime
。
CREATE TABLE `gdata` (
`alarmTypeID` tinyint(4) NOT NULL DEFAULT '0',
`fleetID` smallint(11) NOT NULL,
`fleetGroupID` smallint(11) DEFAULT NULL,
`fleetSubGroupID` smallint(11) DEFAULT NULL,
`deviceID` mediumint(11) NOT NULL,
`vehicleID` mediumint(11) NOT NULL,
`gDateTime` datetime NOT NULL,
`insertDateTime` datetime NOT NULL,
`latitude` float NOT NULL,
`longitude` float NOT NULL,
`speed` smallint(11) NOT NULL
-- (see full text)
) ;
ALTER TABLE `gdata`
ADD PRIMARY KEY (`alarmTypeID`,`vehicleID`,`gDateTime`),
ADD KEY `gDateTime` (`gDateTime`),
ADD KEY `fleetID` (`fleetID`,`vehicleID`,`gDateTime`);
COMMIT;
Run Code Online (Sandbox Code Playgroud)
这是报警表
CREATE TABLE `alarm` (
`alarmTypeID` tinyint(4) NOT NULL,
`vehicleID` mediumint(9) NOT NULL,
`gDateTime` datetime NOT NULL,
`insertDateTime` datetime NOT NULL,
`alarmValue` varchar(5) NOT NULL,
`readWeb` enum('n','y') NOT NULL DEFAULT 'n',
`readWebDateTime` datetime NOT NULL,
`readMobile` enum('n','y') NOT NULL DEFAULT 'n',
`readMobileDateTim` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `alarm`
ADD PRIMARY KEY (`alarmTypeID`,`vehicleID`,`gDateTime`);
COMMIT;
Run Code Online (Sandbox Code Playgroud)
一切看起来都不错,但最近我在搜索相关主题时发现了一些讨论https://www.quora.com/Is-it-a-bad-idea-to-have-a-primary-key-on- 3 列或更多列反对复合主键,并且倾向于使用自动增量,主要用于插入目的。有人可以对此进行更多说明以保持主键的复合键或移回自动增量吗?
复合键没有任何问题。但是,您必须考虑如何InnoDB
存储数据。
引用上面链接的文档:
每个 InnoDB 表中的数据分为页。构成每个表的页面排列在称为 B 树索引的树数据结构中。表数据和二级索引都使用这种类型的结构。表示整个表的 B 树索引称为聚集索引,它根据主键列进行组织。索引数据结构的节点包含该行中所有列的值(对于聚集索引)或索引列和主键列(对于二级索引)。
也就是说,InnoDB 将根据您的PRIMARY KEY
. 如果您插入的数据的 PK 不断增加,则不会发生页面碎片。这将始终发生在AUTO_INCREMENT
. 如果您按时间顺序插入数据(即gDateTime
始终单调递增),请将构成您的 PK 的列的顺序更改为:
PRIMARY KEY (`gDateTime`, `alarmTypeID`, `vehicleID`)
Run Code Online (Sandbox Code Playgroud)
...将具有相同的优势,因为不必“在其他行中间放置一个新行”(这意味着,B 树不会因每个插入而碎片化)。
但是:如果您从其他(相关)表中引用此表,则必须在引用表中始终存储 PK ( gDateTime
, alarmTypeID
, vehicleID
)。这意味着您每次都可以节省 7 或 8 个字节的存储空间。复合 PK 将使用 2 + 1 + 8 = 11 个字节的信息(可能由于对齐而使用了 12 个字节);而 an INT UNSIGNED AUTO_INCREMENT
,您将在引用表中仅使用 4 个字节。您的 PK 仅限于 2^32 个不同的值。如果您需要超过 2^32 个值,您将需要BIGINT AUTO_INCREMENT
2^64(我还没有找到一个实际案例,这还不够大)。
这是否有意义,很大程度上取决于您的特定场景。
归档时间: |
|
查看次数: |
7682 次 |
最近记录: |