当我创建DECIMAL
具有默认精度设置的列时,在 H2 Web 控制台中,该列被定义为DECIMAL(65535, 32767)
,命令“show columns from ...”给了我DECIMAL(65535)
。
H2 中的小数数据类型映射到BigDecimal
(来自 H2 文档),但我不确定 H2 如何处理它。
如果我使用较小的精度,是否有任何性能提升?
当我创建DECIMAL
具有默认精度设置的列时,在 H2 Web 控制台中,该列被定义为DECIMAL(65535, 32767)
,命令“show columns from ...”给了我DECIMAL(65535)
。
H2 中的小数数据类型映射到BigDecimal
(来自 H2 文档),但我不确定 H2 如何处理它。
如果我使用较小的精度,是否有任何性能提升?
要了解有关DECIMAL
H2 数据类型的更多信息,请org.h2.value.ValueDecimal
检查h2-x.y.z.jar
.
仔细看看你会看到默认值是你提到的:
/** The default precision for a decimal value. */
static final int DEFAULT_PRECISION = 65535;
/** The default scale for a decimal value. */
static final int DEFAULT_SCALE = 32767;
仔细观察ValueDecimal
:
private final BigDecimal value;
和org.h2.store.Data
:
public Value readValue() {
...
case Value.DECIMAL: {
int scale = readVarInt();
int len = readVarInt();
byte[] buff = DataUtils.newBytes(len);
read(buff, 0, len);
BigInteger b = new BigInteger(buff);
return ValueDecimal.get(new BigDecimal(b, scale));
}
你可以看到 aDECIMAL
只不过是 a BigDecimal
。也就是说,您将面临的所有性能问题java.math.BigDecimal
,您将面临DECIMAL
。
如果你真的很喜欢它,你可以进一步学习这门课,看看精度/规模究竟扮演了什么角色。
如果我们去看文档,所有 H2 关于DECIMAL
数据类型和性能的说法是:
DECIMAL
/NUMERIC
类型比REAL
and类型更慢并且需要更多的存储空间DOUBLE
。
所以他们说这是事实。
但既然你在谈论性能,我们可以切入正题,做一些测试。测试类的代码如下,让我们来看看输出/结果:
TYPE INSERT time COUNT() time .db Size (kb)
DECIMAL(20,2) 6.978 0.488 27958.0
DECIMAL(100,2) 4.879 0.407 25648.0
DECIMAL(100,80) 8.794 0.868 90818.0
DECIMAL(60000,2) 4.388 0.4 25104.0
DECIMAL(1000,900) 112.905 6.549 1016534.0
REAL 5.938 0.318 22608.0
DOUBLE 6.985 0.416 25088.0
如您所见,当精度发生变化时,时间或存储大小没有明显变化(精度20
大约需要与时间/大小一样多的时间/大小60000
!)。
事情是当你改变规模。这是您应该担心的;如您所见,时间DECIMAL(100,2)
和DECIMAL(100,80)
存储量都大大增加。
DECIMAL(1000,900)
需要超过1 GB (!!!) 来存储完全相同的值。
最后,在上面的测试中,似乎REAL
并DOUBLE
没有好太多DECIMAL
(它们甚至可能看起来更糟)。但是尝试更改插入的行数(for
测试方法中的循环),数字越大,它们似乎响应越好。
*DECIMAL(20,2)
似乎比其他的更慢/更大。那不是真的。实际上,无论您选择先运行什么,都会稍微慢一些/更大一些。去搞清楚...
public class Main {
public static void main(String[] a) throws Exception {
Class.forName("org.h2.Driver");
System.out.format("%-18s%-15s%-15s%-15s", "TYPE", "INSERT time", "COUNT() time", ".db Size (kb)");
System.out.println();
testPerformance("TEST_DECIMAL_20_2", "DECIMAL(20,2)");
testPerformance("TEST_DECIMAL_100_2", "DECIMAL(100,2)");
testPerformance("TEST_DECIMAL_100_80", "DECIMAL(100,80)");
testPerformance("TEST_DECIMAL_60000_2", "DECIMAL(60000,2)");
testPerformance("TEST_DECIMAL_1000_900", "DECIMAL(1000,900)");
testPerformance("TEST_REAL", "REAL");
testPerformance("TEST_DOUBLE", "DOUBLE");
}
private static void testPerformance(String dbName, String type) throws SQLException {
System.out.format("%-18s", type);
Connection conn = DriverManager.getConnection("jdbc:h2:" + dbName, "sa", "");
conn.createStatement().execute("DROP TABLE IF EXISTS TEST;");
conn.createStatement().execute("CREATE TABLE TEST (DECTEST " + type +" )");
long insertStartTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
conn.createStatement().execute("INSERT INTO TEST (DECTEST) VALUES (12345678901234.45)");
}
double insertTime = ((double)(System.currentTimeMillis()-insertStartTime))/1000;
System.out.format("%-15s", insertTime+"");
long countStartTime = System.currentTimeMillis();
conn.createStatement().executeQuery("select COUNT(DECTEST) from TEST");
double countTime = ((double)(System.currentTimeMillis()-countStartTime))/1000;
System.out.format("%-15s", countTime+"");
conn.close();
double fileSize = (double)new File(dbName+".h2.db").length() / 1024;
System.out.format("%-15s", fileSize+"");
System.out.println();
}
}
H2中的精度和比例DECIMAL
是可选的。如果您在未指定精度/比例的情况下创建列,则性能不受影响,存储不受影响,您可以插入任何值并返回相同的值:
create table test(data decimal);
insert into test values(1.345);
select * from test;
> 1.345