【发布时间】:2015-11-30 23:18:46
【问题描述】:
我正在创建一个包含非常大 (100M+) 组历史记录的表。每条记录都带有时间戳,并且保证永远不会更改。
主要的读取操作将是查询特定日期/日期时间之间的所有记录,这主要会导致总记录的一小部分 - 几天的时间跨度,通常来自特定控制器。
由于数据是按顺序写入的,因此时间戳保证不会递减。
CREATE TABLE history
(
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
controller_id INT(11) UNSIGNED,
node_address SMALLINT UNSIGNED,
p1 SMALLINT,
p2 SMALLINT,
state BOOL,
created DATETIME
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
为简单起见,我们可以忽略其他约束并假设一个典型的查询是这样的:
SELECT * FROM `history` WHERE `created` BETWEEN <date_time_1> AND <date_time_2>
创建索引会占用大量空间,并且可能会降低插入性能,但如果没有它,可能会执行全表扫描,使其成为 O(n) 操作,而实际上,O(log(n) ) 就足够了,考虑到数据的限制,通过二分搜索。
有没有办法提示 MySQL(或其他数据库引擎),将单调递增的字段视为此类并执行快速查找,而不使用索引?
有没有更好的方法来实现这一点?
澄清:
虽然创建索引是完全可能的,而且我可能会在必要时使用它,但找到一种避免它的有效替代方法是问题的主题。希望是一种不涉及大量额外维护或存储开销的方法。
因此,这个问题主要是出于好奇而提出的,希望有人遇到类似的情况并想出一些办法来避免创建索引。
【问题讨论】:
-
不要试图超越标准技术。另外,请停下来重新考虑一下您所问的含义...如果插入的值确实是单调的,那么插入该索引的性能问题几乎不存在,不是吗?
-
我同意理论上对插入的性能影响应该可以忽略不计,但我担心这过于乐观。我相信树的足够大的部分必须在内存中蜜蜂才能使影响不存在,但是随着索引变大,我怀疑它不适合可用内存并将被交换,从而导致缓存会影响性能的失误。这就是为什么我一直在寻找一种方法来完成这种暗示。我想这是一个很长的镜头,但仍然值得一问。
-
剧透警报 :) 我想不出这样的机制。但是,除非您需要自动递增的“id”列,否则您也许可以将 (created,controller_address,node_id) 设为主键,因为无论如何这始终是 InnoDB 中的聚集索引……第一个是免费的……但最终我认为你过早地优化了一个主要是理论上的问题,特别是当你以索引顺序插入并且从不修改时。让我们看看是否有人提出了我们没想到的答案。
-
谢谢。我也希望如此,我会考虑复合主键聚集索引:)
-
这里的关键问题是表中的记录不是有序结构,而索引是。对有序结构执行的算术运算很便宜,我们可以在几个 I/O 中找到我们需要的记录。表不是有序结构。当然,它是按顺序编写的,但是如果您想找到等于某物或某物之间的记录,则必须遍历整个表才能找到它,因为您不知道必须比较哪些可能的值。指数以空间换取速度并允许这些操作。答案是 - 不,你不能。
标签: mysql database performance indexing