BLOB vs. VARCHAR用于在MySQL表中存储数组

我有一个设计决定,我正在寻找一些最佳实践建议。 我有一个java程序,需要在MySQL数据库中存储大量(每天几百个)浮点数组。 数据是固定长度的Double数组,长度为300.我可以看到三个合理的选项:

  1. 将数据存储为BLOB。
  2. 序列化数据并将其存储为VARCHAR。
  3. 将数据作为二进制文件写入磁盘并存储对它的引用。

我还要提一下,这些数据将被频繁读取和更新。

我想使用BLOB,因为这是我过去所做的,它似乎是最有效的方法(例如,保持固定的宽度,不需要转换为逗号分隔的字符串)。 然而,我的同事坚持认为我们应该序列化和使用varchar,原因似乎主要是教条。

如果其中一种方法比另一种更好,那么Java或MySQL具体的原因是什么?

像这样存储BLOB(参见下面的代码示例)。 我认为这可能比使用java序列化更好,因为java的内置序列化将需要2427个字节,非Java应用程序将更难处理数据。 也就是说,如果将来有任何非java应用程序查询数据库……如果没有,那么内置序列化就少了几行。

 public static void storeInDB() throws IOException, SQLException { double[] dubs = new double[300]; ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(bout); for (double d : dubs) { dout.writeDouble(d); } dout.close(); byte[] asBytes = bout.toByteArray(); PreparedStatement stmt = null; // however we normally get this... stmt.setBytes(1, asBytes); } public static double[] readFromDB() throws IOException, SQLException { ResultSet rs = null; // however we normally get this... while (rs.next()) { double[] dubs = new double[300]; byte[] asBytes = rs.getBytes("myDoubles"); ByteArrayInputStream bin = new ByteArrayInputStream(asBytes); DataInputStream din = new DataInputStream(bin); for (int i = 0; i < dubs.length; i++) { dubs[i] = din.readDouble(); } return dubs; } } 

编辑:我希望使用BINARY(2400),但MySQL说:

 mysql> create table t (a binary(2400)) ; ERROR 1074 (42000): Column length too big for column 'a' (max = 255); use BLOB or TEXT instead 

您是否有理由不创建子表,以便每行存储一个浮点值而不是数组?

假设您每天存储一千个300个元素的数组。 这是每天300,000行,或每年1.095亿行。 没有什么可以打喷嚏,但在MySQL或任何其他RDBMS的能力范围内。


你的意见:

当然,如果订单很重要,您可以为订单添加另一列。 以下是我设计表格的方法:

 CREATE TABLE VectorData ( trial_id INT NOT NULL, vector_no SMALLINT UNSIGNED NOT NULL, order_no SMALLINT UNSIGNED NOT NULL, element FLOAT NOT NULL, PRIMARY KEY (trial_id, vector_no), FOREIGN KEY (trial_id) REFERENCES Trials (trial_id) ); 
  • 一行矢量数据的总空间:300x(4 + 2 + 2 + 4)= 3600字节。 加上InnoDB记录目录(内部东西)的16个字节。

  • 如果序列化300个浮点数= 1227个字节的Java数组,则总空间是多少?

因此,通过存储arrays可节省大约2400字节或67%的空间。 但假设您有100GB的空间来存储数据库。 存储序列化数组允许存储8750万个向量,而标准化设计仅允许存储2980万个向量。

你说你每天存储几百个向量,所以你将在81年而不是239年内填满100GB的分区。


重新评论: INSERT的性能是一个重要的问题,但你每天只存储几百个向量。

大多数MySQL应用程序每秒可以实现数百或数千个插入而无需过多的魔法。

如果您需要最佳性能,请参阅以下内容:

  • 显式交易
  • 多行INSERT语法
  • INSERT DELAYED(如果你仍然使用MyISAM)
  • 加载数据传输
  • ALTER TABLE DISABLE KEYS,执行插入,ALTER TABLE ENABLE KEYS

在您最喜爱的搜索引擎上搜索“每秒插入mysql”这个短语,阅读许多文章和博客,并谈论这个问题。

如果您只想将数据存储为Java数组的二进制转储,那么请务必使用BLOB。 您的朋友可能会建议不要这样做,因为您可能希望某些非Java程序稍后使用该信息,因此二进制转储可能很难解释。

通过序列化到VARCHAR,您可以了解数据格式,并可以使用任何应用程序轻松读取它。

当然,如果您有可能想要操纵或报告各个浮点数,它们应该以数据库友好的格式存储。 换句话说, 不是二进制转储, 不是序列化, 不是 CSV列。

以Codd的意图存储它们,以第三范式存储。

顺便说一句,每天有几百个300元素的浮点数组不是一个大数据库。 从使用DB2在大型机上工作的人那里获取它,大多数DBMS将很容易处理这种卷。 我们每天都会在我们的应用程序中收集数千万行,甚至不会出汗。

使用数据库存储一维数组是痛苦的屁股! 甚至更多使用rdm所存储的数据之间没有关系。 对不起,但最好的解决方案imho是使用文件,只是按照你喜欢的方式写数据。 二进制或txt。 因此,300xsize的long或300×1行的txt是一个arrays。