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

时间:2010-06-24 00:46:32

标签: java mysql arrays blob varchar

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

  1. 将数据存储为BLOB。
  2. 序列化数据并将其存储为VARCHAR。
  3. 将数据作为二进制文件写入磁盘,并存储对它的引用。
  4. 我还应该提一下,这些数据将会被频繁阅读和更新。

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

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

4 个答案:

答案 0 :(得分:14)

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

假设您每天存储一千个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数组,则总空间是什么?

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

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


重新评论:Performance of INSERT是一个重要问题,但每天只存储几百个矢量。

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

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

  • 显式交易
  • 多行INSERT语法
  • INSERT DELAYED(如果您仍然使用MyISAM)
  • LOAD DATA INFILE
  • ALTER TABLE DISABLE KEYS,执行插入,ALTER TABLE ENABLE KEYS

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

答案 1 :(得分:8)

像这样存储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

答案 2 :(得分:3)

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

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

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

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

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

答案 3 :(得分:0)

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