【问题标题】:BLOB vs. VARCHAR for storing arrays in a MySQL table用于在 MySQL 表中存储数组的 BLOB 与 VARCHAR
【发布时间】:2011-03-07 14:23:23
【问题描述】:

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

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

我还应该提到,这些数据将被频繁读取和更新。

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

如果其中一种方法比另一种更好,是 Java 还是 MySQL 特有的原因?

【问题讨论】:

  • 要真正回答您关于 VARCHAR 与 BLOB 的具体问题:选择 BLOB! VARCHAR 将占用更多空间并且操作起来会更慢。操作起来也很尴尬(总是来回转换)。至于关于 300 ROWS 与 1 ROW 的讨论,如下面的 Bill Karwin 所示:300 行方法将占用至少 2 倍的空间,而且速度会更慢。我也怀疑操作起来会更尴尬; IE。您将需要在应用程序中编写更多代码来处理这种方法。 BLOB在这里很好。单独留下工作代码也很好。
  • +2 给 Julius 以回答具体问题,+1 给 Bill 以获得建议

标签: java mysql arrays blob varchar


【解决方案1】:

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

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


你的cmets:

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

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 字节。加上 16 字节的 InnoDB 记录目录(内部内容)。

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

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

您说您每天存储几百个向量,因此您只需 81 年而不是 239 年即可填满 100GB 分区。


回复您的评论:Performance of INSERT 是一个重要问题,但您每天只存储几百个向量。

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

如果您需要最佳性能,请注意以下几点:

  • 显式交易
  • 多行插入语法
  • 延迟插入(如果您仍在使用 MyISAM)
  • 加载数据文件
  • ALTER TABLE DISABLE KEYS,插入,ALTER TABLE ENABLE KEYS

在您最喜欢的搜索引擎上搜索短语“mysql inserts per second”以阅读许多关于此的文章和博客。

【讨论】:

  • 1.) 也许我应该说一个 300 维向量而不是数组。换句话说,顺序很重要,绝对没有理由在没有其他元素的情况下访问单个元素。获取和处理 300 行似乎要慢一些。我错过了什么吗? 2.) 如果我告诉他我想每天在一张表中添加 300k 行,我的教条主义同事会大发雷霆。他之前非常反对我的一个设计想法,因为它需要每天将 25k 行添加到交叉表中。他有意见还是我还是应该这样做?
  • 好吧,我可能应该再次提到数据存储不是这里真正的问题,而是速度。您的解决方案不是需要 300 倍的 INSERT 操作到具有多个索引的表中吗?
【解决方案2】:

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

【讨论】:

  • 如果我们有一个字符串数组而不是将值存储为双精度值的数组怎么办?相同的方法是否有效,还是有更好的方法?
【解决方案3】:

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

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

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

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

顺便说一句,每天几百个 300 元素的浮点数组并不是一个大数据库。从使用 DB2 在大型机上工作的人那里得到它,大多数 DBMS 都可以轻松处理这种卷。我们每天将数千万行数据收集到我们的应用程序中,甚至不费吹灰之力。

【讨论】:

    【解决方案4】:

    使用数据库来存储一维数组实在是太麻烦了! 甚至更多使用 rdm ,其中存储的数据之间没有关系。 抱歉,恕我直言,最好的解决方案是使用文件并按照您喜欢的方式写入数据。 二进制或txt。 因此 300xsize 长或 300x1 行 txt 是一个数组。

    【讨论】:

      猜你喜欢
      • 2011-03-23
      • 2010-11-16
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 2018-10-24
      • 2011-04-10
      • 2018-05-07
      • 2021-07-02
      相关资源
      最近更新 更多