使用一个表的多个索引优化数据库性能

时间:2019-01-24 14:03:56

标签: mysql sql database database-performance

我有关于我在简单的一对表中存储的许多项目的时间序列数据(在此玩具示例中)。现在,这是在MySQL中完成的,但是如果有足够充分的理由尝试在不同的DBMS中解决我的问题,我会不知所措!

ITEM表具有一个主键和一个可以视为描述的类似文本的列,我们将其称为descrDATAPOINT表具有一个主键和其他3列:ITEM表中的外键(称为fk_item),日期时间我将调用timestamp并进行浮动我们称为value的值。此外,在(fk_item, timestamp)列对上存在联合唯一性约束(我们只希望在给定时间给定项目中DB中有一个值)。

要在其上加上实数,DATAPOINT表大约有10亿行,这是由于每10k个不同项大约有10万行。

我的问题是关于在这种情况下优化读写性能的能力,以及实施该唯一性约束的最佳方法。

从此数据库中进行的典型读取将涉及少量项目(半打?),我们希望针对这些项目获得给定日期时间范围内的所有值(每个项目包含大约1k点)。为此,拥有一个(fk_item, timestamp)的索引并对该索引执行联合唯一性标准将非常方便。这种读物背后的动机是:“我想为这3年范围制作2或3个项目的折线图”。

但是,该数据库的典型写入看起来非常不同。这将是为数千个项目中的每一个插入单个数据点,所有项目都具有相同(或少量)时间戳。这种写法的动机可以直观地认为是:“我想为每一项添加昨天的数据点”。因此,对于这种类型的写入,拥有一个(timestamp, fk_item)的索引并对该索引执行唯一性限制会更实际。

重要的是,对于我的数据和硬件规模而言,这些索引都无法完全放入RAM。

通常,绝大多数写操作每天都在短时间内发生:即,在每天结束时,当天的所有数据都会在15分钟内写入,然后全天进行读操作(但通常不在那15分钟之内。

因此,据我了解,如果我使用经过读取优化的(fk_item, timestamp)索引构建表(并在其中放置唯一性约束),那么我的典型读取将非常方便。但是我担心我的写入会很慢,因为我们将需要以非连续的方式更新索引。但是,如果我用写优化的(timestamp, fk_item)索引构建表(并在其中放置唯一性约束),那么我的典型写入将很快,但是典型的读取会受到影响。

有什么办法可以做到两全其美吗?例如,如果我建立两个索引:(fk_item, timestamp) (timestamp, fk_item)并将唯一性 only 放在两个索引中的最后一个,那会很好?否则,写操作仍将以“慢”的速度进行,因为即使存在写优化索引(例如,检查唯一性约束),读优化索引也需要在任何插入上进行更新,并且该更新将是不连续的?

谢谢!

1 个答案:

答案 0 :(得分:0)

简短答案:仅server.use( session({ secret: "secretsssss", rolling: false, resave: false, saveUninitialized: false, cookie: { sameSite: false, // i think this is default to false maxAge: 60 * 60 * 1000 } }) );

长答案:

唯一性而言,(fk_item, timestamp)(fk_item, timestamp)是相同的。尽管它们都同样出色地声明了唯一性,但是它们都对 being 唯一性很着迷。有一天,某个特定的物品会在同一秒内显示两次。

您确实提到了“昨天”。因此,如果该条目确实是 day 的小计,则(timestamp, fk_item)是合理的。

建立索引时,最好将日期/时间项设为 last 。这样(fk_item, date)可以使用该索引。写作并不在乎(什么)事物的顺序。

WHERE fk_item = 123 AND date BETWEEN ... AND ...呢?它是,但MySQL的定义为PRIMARY KEY和一个UNIQUE。因此,如果INDEX是合理的,则将其设为PK。这将使需要查看特定项目几行的查询更加高效。

“我想为此3年范围制作2或3个项目的折线图”。 -如果涉及数百万行,则说明您对架构的设计效率低下。您需要建立并维护一个汇总表,其中包含每个项目的每日值。那么它将是数百行,而不是数百万行–更加可行。

返回(fk_item, date)。如果有1万个不同的项目和INSERTs,则表中将出现1万个插入位置。这实际上是可以的,并且将与其他订购大致相同的速度。

最好PRIMARY KEY(fk_item, date)或多行INSERTs来完成每日LOAD DATA INFILE

我从MySQL的角度讲。我说的一些(也许不是全部)适用于其他产品。

除非您打算清除“旧”数据,否则

INSERTs对于MySQL是一个无用的主意。 (我不能代表Posgres。)

如果随机插入行,则可能会遇到不切实际的性能问题。这是因为您的实际情况将减少“随机性”。您今天PARTITIONing的工作地点只有1万个,而不是10亿个。明天,它将是“相同”的10K点。

“应该如何构建这样的表”-最小化数据类型(例如,不要将8字节的INSERTs用于yes / no标志);提供最佳PK(我建议使用BIGINT)。但是您必须具有暂定(item, day)才能确定二级索引。在适当的地方进行归一化(SELECTs),但不要过度归一化(日期)。