5

当我创建DECIMAL具有默认精度设置的列时,在 H2 Web 控制台中,该列被定义为DECIMAL(65535, 32767),命令“show columns from ...”给了我DECIMAL(65535)

H2 中的小数数据类型映射到BigDecimal(来自 H2 文档),但我不确定 H2 如何处理它。

如果我使用较小的精度,是否有任何性能提升?

4

2 回答 2

6

要了解有关DECIMALH2 数据类型的更多信息,请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类型比REALand类型更慢并且需要更多的存储空间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 (!!!) 来存储完全相同的值。

最后,在上面的测试中,似乎REALDOUBLE没有好太多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();
    }
}
于 2013-04-30T04:16:57.117 回答
3

H2中的精度和比例DECIMAL是可选的。如果您在未指定精度/比例的情况下创建列,则性能不受影响,存储不受影响,您可以插入任何值并返回相同的值:

create table test(data decimal);
insert into test values(1.345);
select * from test;
> 1.345
于 2013-04-30T05:01:26.270 回答