【问题标题】:MySql primary key doesn't consume any sizeMySql 主键不消耗任何大小
【发布时间】:2017-07-24 07:46:42
【问题描述】:

我有这两个表架构:

CREATE TABLE `myTable` (
  id int(11) NOT NULL AUTO_INCREMENT,
  lat double NOT NULL,
  lng double NOT NULL,
  date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  mobile bigint(11) unsigned NOT NULL,
  date_updated datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`id`),
  KEY `IDX_Datee` (`mobile`,`date`),
  CONSTRAINT `FK_DeviceLocationss` FOREIGN KEY (`mobile`) REFERENCES `device` (`serial`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

这是第二个:

CREATE TABLE `myTable2` (
  lat double NOT NULL,
  lng double NOT NULL,
  date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  mobile bigint(11) unsigned NOT NULL,
  date_updated datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY `IDX_Datee2` (`mobile`,`date`),
  CONSTRAINT `FK_DeviceLocationss2` FOREIGN KEY (`mobile`) REFERENCES `device` (`serial`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

到目前为止,每个表中大约有 4,000,000 条记录, 所以我正在尝试构建最合适的架构,它更快且存储消耗更少。

当我检查MySql Workbeanch 中每个Table 的状态时,我有点困惑:

第一个表:

第二张表

当我将IDX_Datee 键从Index 更改为Primary 时,它不会占用任何空间。

我相信第二种模式对我来说更好,但我不太了解这种差异。

谁能解释一下?

【问题讨论】:

    标签: mysql indexing mysql-workbench database-schema


    【解决方案1】:

    该表是索引组织的。数据记录按索引顺序存储。 见https://dev.mysql.com/doc/refman/5.5/en/optimizing-primary-keys.html

    “使用 InnoDB 存储引擎,对表数据进行物理组织,以根据主键列或列进行超快速查找和排序”

    所以不需要额外的索引

    【讨论】:

    • 所以在这种情况下,Delete, Update 查询将花费很长时间,对吧?
    • 我不是 mysql 专家,我知道这些来自 Sql-Server 的 IOT。我想说应该没有太大的区别,更新不应该有负面影响,因为它是主键。删除和插入可能需要更多的努力来处理数据并且更少的努力,因为要保持更新的索引更少。最大的优势是每次通过主键访问通常需要较少的外部操作,因为所有数据都已经存在。
    【解决方案2】:

    由PK指定的单个行上的所有操作(选择、插入、删除、更新)将非常快速和高效。向下钻取包含数据并由 PK 组织的 BTree,并且有可以使用的行。

    PK 占用很小的空间,就像任何 BTree 都比叶节点多一样。作为一个经验法则,MySQL 的 BTrees(数据或索引)的扇出约为 100。也就是说,每个节点下有大约 100 个节点。这意味着对于“其余”的 PK 开销,非叶节点只有大约 1% 的开销。

    16KB / 61 大约是 268——你的“扇出”。

    对于初学者,我建议DOUBLE(8 个字节)对于经纬度来说是非常过分的,除非您试图区分狗身上的一种跳蚤和另一种跳蚤。这是my table 的经纬度表示选择。

    INT 是 4 个字节。如果您确定不会超过 1600 万,请将 PK 更改为 MEDIUMINT UNSIGNED(3 个字节)。 (我认为这太冒险了。)

    PK 的大小具有双重重要性,因为它包含在每个辅助密钥中。

    如果(mobile, date) 是唯一的,它也可能是PK。这会减少 两个 id 的副本,并且加快基于 mobile 的查询。

    如果mobile 包含电话号码,那么有些号码将不适合。最好使用 DECIMAL(11) 占用 5 个字节; (13) 需要 6。相反,如果 mobile 是其他表中的 AUTO_INCREMENT,则可能甚至 SMALLINT UNSIGNED每个副本,每个表)会更好。

    您的第一个表有 4 个额外的列(相对于第二个表):id--twice、mobiledate

    【讨论】:

    • 谢谢你,你的信息非常好,但我不明白你从哪里得到第二部分的16KB
    • InnoDB 块为 16KB。所有 InnoDB 数据和索引都存储在具有 16KB 块的 BTree 中。 (如果您需要复习 BTree,请参阅 Wikipedia。)
    猜你喜欢
    • 2013-03-19
    • 2017-10-07
    • 2012-12-09
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    相关资源
    最近更新 更多