确定 MariaDB 中十进制数据类型列所需的精度和小数位数

Determining required precision and scale for decimal data type columns in MariaDB

提问人:neucassi 提问时间:10/5/2023 最后编辑:Bill Karwinneucassi 更新时间:10/7/2023 访问量:73

问:

我有大量的MariaDB 10.6表,有几列和数百万行。这些列的精度 () 和小数位数 () 曾经被设置为不切实际的高级别,只需容纳每个可能的输入,例如 .decimal(P,D)PDdecimal(24,10)

现在,我想根据这些表中的实际数据确定所需的值和值。PD

我能想到的最好的是

SELECT CEIL(LOG10(MAX(col))) AS maxI,
       MAX(CEIL(LOG10(CAST(REVERSE(SUBSTR(CAST(col % 1 AS VARCHAR(12)), 3)) AS INT)))) AS maxD
FROM tbl;

其中是数据类型为、最大整数部分和小数点后最大有效位数的列(so)。coldecimal(24,10)maxImaxPmaxP = maxI + maxD

虽然它确实有效,但速度很慢,我想知道是否有更有效的方法可以到达那里。

MariaDB 十进制 精度

评论

1赞 Barmar 10/5/2023
我会用.如果有索引,它可以快速计算出最大值。CEIL(LOG10(MAX(col)))col
0赞 Barmar 10/5/2023
即使它没有,也不必调用每一行,这很昂贵。LOG10
0赞 Barmar 10/5/2023
我想不出任何有效的方法来获得.maxD
1赞 Barmar 10/5/2023
当然,这对我来说是愚蠢的。您需要删除尾随零,这可以通过 来完成。REGEXP_REPLACE
1赞 Bill Karwin 10/5/2023
MariaDB 不是 MySQL。我进行了编辑,以更清楚地表明您使用的是 MariaDB,而不是 MySQL。

答:

1赞 Georg Richter 10/5/2023 #1

使用精确数字时,请勿使用双精度函数(如 LOG10),以避免出现警告和舍入错误。

计算小数点前的最大位数非常简单,因为优化器可以在不触及索引的情况下处理。对于无符号小数,您可以使用 ,对于有符号小数,您必须使用 和 :MAX()MIN()MAX()

select @maxI1:=LENGTH(TRUNCATE(MIN(col1),0)), @maxI2:=LENGTH(TRUNCATE(MAX(col1),0)) FROM tbl;

最十进制的数字有记录。 所以第二句话是:MAX(col1 - TRUNCATE(col1,0))

SELECT IF(@maxI1 > @maxI2, @maxI1, @maxI2) as maxI,
       LENGTH(TRIM(MAX(col1 - TRUNCATE(col1, 0)))+0) -2 as maxD
FROM tbl;

速度比较(7 Mio行):

SELECT CEIL(LOG10(MAX(col1))) AS maxI, MAX(CEIL(LOG10(CAST(REVERSE(SUBSTR(CAST(col1 % 1 AS VARCHAR(12)), 3)) AS INT)))) AS maxD FROM tbl;
+------+------+
| maxI | maxD |
+------+------+
|   13 |   10 |
+------+------+
1 row in set, 40964 warnings (6.166 sec)

与。

SELECT @maxI1:=LENGTH(TRUNCATE(MIN(col1),0)) as maxI1, @maxI2:=LENGTH(TRUNCATE(MAX(col1),0)) as maxI2 FROM tbl;
+-------+-------+
| maxI1 | maxI2 |
+-------+-------+
|     5 |    13 |
+-------+-------+
1 row in set (0.000 sec)

SELECT IF(@maxI1 > @maxI2, @maxI1, @maxI2) as maxI, LENGTH(TRIM(MAX(col1 - TRUNCATE(col1, 0)))+0) -2 as maxD FROM tbl;
+------+------+
| maxI | maxD |
+------+------+
|   13 |    7 |
+------+------+
1 row in set (4.168 sec)

评论

0赞 neucassi 10/6/2023
我得到了完全不同的结果。如果是 5 并且是 13,那么为什么会是 13?不应该是 2 吗?有了你的解决方案,我既没有得到正确的答案,也没有得到 - 总是等于.@maxI1@maxI2IF(@maxI1 > @maxI2, LENGTH(@maxI1), LENGTH(@maxI2))maxImaxDmaxDD
0赞 neucassi 10/7/2023
这样就解决了 的问题。但仍然等于列的指定比例。maxImaxDD
0赞 Georg Richter 10/7/2023
答案已更新/更正。
0赞 neucassi 10/7/2023
MAX(value - TRUNCATE(value, 0)给我们一个没有整数部分的最大值(例如 0.65),而我们应该找到“最长”的值(0.21746)。我同意@Barmar的观点,即没有办法绕过字符串。