我有一个设计决定,我正在寻找一些最佳实践建议。我有一个java程序,需要在MySQL数据库中存储大量(每天几百个)浮点数组。数据是长度为300的固定长度Double
数组。我可以看到三个合理的选项:
我还应该提一下,这些数据将会被频繁阅读和更新。
我想使用BLOB,因为这是我过去所做的,它似乎是最有效的方法(例如,保持固定宽度并且不需要转换为以逗号分隔的字符串)。然而,我的同事坚持认为我们应该序列化并使用varchar,原因似乎主要是教条主义。
如果其中一种方法比另一种更好,那么Java或MySQL的具体原因是什么?
答案 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应用程序可以实现数百或数千个每秒的插入,而无需过多的魔法。
如果您需要最佳性能,请参阅以下内容:
在您最喜爱的搜索引擎上搜索“每秒插入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是一个数组。