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

Dou*_*oug 16 java mysql arrays varchar blob

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

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

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

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

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

Bil*_*win 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)
);
Run Code Online (Sandbox Code Playgroud)
  • 一行矢量数据的总空间:300x(4 + 2 + 2 + 4)= 3600字节.加上InnoDB记录目录(内部东西)的16个字节.

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

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

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


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

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

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

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

在您最喜爱的搜索引擎上搜索短语"每秒插入一次mysql",阅读许多文章和博客,并谈论这一点.

  • 1.)也许我应该说300维向量而不是数组.换句话说,顺序很重要,没有其余部分就没有理由访问单个元素.看起来获取和处理300行会慢得多.我错过了什么吗?2.)如果我告诉他我想要每天在桌子上添加30万行,我的教条同事会抛出一个合适的东西.他之前严重反对我的一个设计理念,因为每天会有25k行被添加到交叉表中.他有意见还是我应该这样做? (3认同)

Jul*_*eau 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

编辑:我希望使用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
Run Code Online (Sandbox Code Playgroud)