Decimal type design #5274
Replies: 6 comments 2 replies
-
rug looks like it's GPL due to wrapping GNU code so we can't use that right? Are you aware of license compatible crates that do what we need? When I was looking around for cockroach there were a few packages that could represent decimals, but none that could actually operate on them correctly and not slowly (much less fast). I'm on board with any change that increases our correctness, and we can iterate on performance after that. However the next smallest amount of work to get more correctness is maybe huge and we should delay it for as long as possible. From the cockroach/Go/apd perspective, there are two main performance problems.
This is not a small amount of work. On the order of months to get a crate written, tested, and integrated into mz. Are there some specific bugs or user issues that have happened or are preventing new uses of mz? |
Beta Was this translation helpful? Give feedback.
-
We had some questions raised about overflow in I'm not personally facing anything urgent, but it seemed that at some point you want an arbitrary precision thing, for the folks who want to opt in to "certainly correct" answers and out of "best performance/memory use". |
Beta Was this translation helpful? Give feedback.
-
I hope this doesn't sound too mean, but there is one thing not on the list which is "minimize implementation effort", i.e. how much do we want to work to e.g. track precision correctly etc. IIRC that was one of the highest priorities at the time, because we had other things to do. It is now something that could be demoted, and one way forward could be "actually track precision correctly". I can understand that we might prefer APD stuff instead (and I like that too) but e.g. if we needed something working at week's end, we could try and fix what we have. |
Beta Was this translation helpful? Give feedback.
-
As it turns out—I knew this once, but had forgotten— So our options now are:
None of these options are particularly appealing. Neither (1) or (2) uses an optimized memory representation, so they're gonna hurt memory-usage wise: https://github.com/gcc-mirror/gcc/blob/ea74a3f548eb321429c371e327e778e63d9128a0/libdecnumber/decNumber.h#L76-L84 (3) is hard for the obvious reason. (4) starts to look more and more appealing, but the task needs an owner. |
Beta Was this translation helpful? Give feedback.
-
How is (4) not the same as (3)? Cockroach had similar problems with its first decimal implementation. I started fixing a few of them and then realized that it was fundamentally wrong and it would be easier to implement from scratch. Do you have reason to believe that we will be able to fix the current library without it resulting in a full rewrite? I'm also onboard with the argument: just do incremental improvements to address specific bugs and that's good enough. (Although I'm still worried some of those will be rather large due to significant mismatch between what we have and what we need.) |
Beta Was this translation helpful? Give feedback.
-
One thing to note is that most of the modern data ecosystem only supports decimals with precision up to 38 (e.g. Spark, Flink, Arrow, Snowflake) due to using i128s underneath (usually with i64s backing decimals with precision <= 18), so I imagine most users would be comfortable with this limitation, especially if removing this limitation decreases performance for common use cases. Looking at Nubank, even though arbitrary precision |
Beta Was this translation helpful? Give feedback.
-
Our decimal type was added in a hurry back in summer 2019 to get the TPC-H queries working, which make heavy use of decimal types to represent money. As a result their design priorities wound up being:
This is no longer the right priority order. Users expect decimal arithmetic to be exact, even at the boundaries. So correctness should be the top priority. And compatibility with PostgreSQL has shaped up to be more important than compatibility with the SQL standard.
To quickly summarize the current design: decimals are stored as a 128-bit signed integer (Rust's
i128
type). The scale information, i.e., "where the decimal point goes", is stored separately in type of the datum. This is at variance with PostgreSQL, where scale information is carried in the decimal value itself. So where we can say "every datum in this column is a decimal with two decimal places", PostgreSQL can only say "every datum in this column is some decimal", and you have to actually go look at each row in the column to see what its scale is.This design was largely engineered for efficient differential reductions. With a uniform scale, to sum up a pile of decimals, we just drop the decimal values into differential's
diff
field and do a fast, in-place accumulation of a bunch ofi128
s.There are a few limitations with this design across the board:
Carrying decimal scale information in the type does not fit well with PostgreSQL's type system. Decimals are special cased all throughout the planner—in casting logic, in function selection logic, and so on—in order to hack in support for unifying scale information. And the rules for this are ad hoc, since we've been making them up as we go.
There is no good type to hold the accumulation of many decimal values. When we sum int4s, we output an int8. When we sum int8s, we output a decimal. But when we sum decimals... we output another decimal. Hopefully you weren't using all the bits in your i128s.
The precision information in the decimal type is a total joke. It's not used for anything except futzing with the output scale of multiplication and division operations in a really confusing way.
@frankmcsherry recently floated the idea of using arbitrary-precision numbers (e.g. rug) as the backing storage for decimals, rather than
i128
s. I thought it would be good to start sketching out a design for this. Do we still want to keep decimal scale information in the type? Should we look into arbitrary-precision decimal libraries rather than arbitrary-precision integer libraries, to offload even more work? (Last time I looked there didn't seem to be any compelling Rust APD libraries though.) Will the performance hit be acceptable?/cc @frankmcsherry @mjibson
Beta Was this translation helpful? Give feedback.
All reactions