h2 默认 DECIMAL 精度性能

use*_*270 4 sql precision h2 database-performance

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

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

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

acd*_*ior 5

要了解更多关于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;
Run Code Online (Sandbox Code Playgroud)

仔细观察ValueDecimal

private final BigDecimal value;
Run Code Online (Sandbox Code Playgroud)

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));
    }
Run Code Online (Sandbox Code Playgroud)

您可以看到 aDECIMAL只不过是 a BigDecimal。也就是说,您将面临的所有性能问题java.math.BigDecimal,您将面临DECIMAL

如果你真的很喜欢它,你可以进一步研究这门课,看看精度/规模扮演什么角色。

如果我们查看文档,所有 H2 关于DECIMAL数据类型和性能的说法是:

DECIMAL/NUMERIC类型是慢,需要比更多的存储REALDOUBLE类型。

所以他们说这是事实。

但是既然你在谈论性能,我们可以切入正题并做一些测试。测试类的代码如下,让我们看看输出/结果:

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    
Run Code Online (Sandbox Code Playgroud)

如您所见,当精度发生变化时,时间或存储大小没有明显变化(精度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();
    }
}
Run Code Online (Sandbox Code Playgroud)