h2默认DECIMAL精度性能

时间:2013-04-29 09:07:06

标签: sql precision h2 database-performance

当我使用默认精度设置创建DECIMAL列时,在H2网络控制台中,此列定义为DECIMAL(65535, 32767),命令“显示来自...的列”给我DECIMAL(65535)。< / p>

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

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

2 个答案:

答案 0 :(得分:3)

要了解有关H2的DECIMAL数据类型的更多信息,请检查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));
    }

您可以看到DECIMAL只不过是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    

如您所见,精度更改时,时间或存储大小没有明显变化(精度20所需的时间/大小与60000大致相同!)。

当你改变比例时。这是你应该担心的;正如您所看到的,DECIMAL(100,2)DECIMAL(100,80)在时间和存储方面都有显着增长。

DECIMAL(1000,900)需要超过 1千兆字节(!!!)才能存储完全相同的值。

最后,在上面的测试中,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();
    }
}

答案 1 :(得分:3)

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

create table test(data decimal);
insert into test values(1.345);
select * from test;
> 1.345