我们先看一下这几个sql在hive中的返回值:
- hive中整数默认给int类型
- 带有小数位的给double类型
- 可以通过cast(num as decimal(n,m)) 指定数字类型
- int类型是最弱的类型,它和其他两个操作后会被转换
- double是最强的类型,和其他两个类型操作时会全部转换成dluble类型
- 使用double运算时可能会导致精度丢失,如对精度要求较高,建议全都换成decimal类型之后再做操作。
select cast('0.00407' as decimal(18,6))*2500 --10.175
select cast('0.00407' as decimal(18,6))*cast(2500 as decimal(18,2)) --10.175
select cast('0.00407' as decimal(18,6))*cast(2500 as double) -- 10.174999999999999
explain select 200; --返回值类型:int
explain select 200.00; --返回值类型:double
explain select 200*200.00 --返回值类型:double
explain select 200*cast(200.00 as decimal(18,2)) --返回值类型:decimal
explain select 200.00*cast(200.00 as decimal(18,2)) --返回值类型:double
- 两个declimal计算不会造成精度丢失
- double和decimal计算可能造成精度缺失
1、hive将字符串默认转换成double类型进行计算
- 执行一下代码:
--'0.00407' 是double,2500 是int类,结果是double类
explain select '0.00407'*2500 -->10.1749999999
- 执行计划
- 可以看到,hive将字符串 ‘0.0407’ 转换成 double类型,最终输出值是: 10.1749999999
2、将字符转换成decimal后再计算
- 执行下面代码:
--2500 是int类型,和decimal类行计算后为 decimal
explain select cast('0.00407' as decimal(18,6))*2500 --> 10.175
- 执行计划
- 将字符串 ‘0.0407’ 转换成 decimal类型之后再计算,结果为: 10.175
decimal 运算先后导致的精度丢失
- hive中即使数值都是decimal,也有可能造成精度缺失 。
- 因为下一步的计算是以上一个计算结果为基础的,所以任何一部出现无法准确表达的数值时都可能造成精度缺失
select 100/12*6 --50.0
select cast(100 as decimal(18,2))/12*6 --49.999998
select cast(100 as decimal(18,2))/cast(12 as decimal(18,2))*cast(6 as decimal(18,2)) --49.999998
select cast(100 as decimal(18,2))*6/12 --50
- 100 /12 *6 这算式在逻辑上与 100 * 6/12 和 100/2 等价,但是100/12不能尽除,导致中间出现中间值:8.33333333333333 导致最终结果丢失精度,结果为:49.999998
- 对于decimal类型来说,计算时应尽量让乘法在除法前计算
总结
- 虽然两个代码的返回值是:10.1749999999 、 10.175 看上去差异很小,但如果将数值通过round函数精确到两位数,则分别返回 10.17 和 10.18 。在金融领域查一分钱的话还是需要注意的,很可能造成资金不对等。
- hive中double和decimal两个类型计算会返回double,有可能造成精度缺失。应该把两个计算值都转换成decimal类型。
- 对于decimal类型来说,计算时应尽量让乘法在除法前计算,减少中间值无法精确表示的情况。
高精度计算时,尽量多保留两位小数,并吧数据转换成decimal类型后再做计算,以免精度丢失