Uh oh!
There was an error while loading. Please reload this page.
[SPARK-28610][SQL] Allow having a decimal buffer for long sum - #25347
[SPARK-28610][SQL] Allow having a decimal buffer for long sum#25347mgaido91 wants to merge 6 commits into
Conversation
SparkQA
commented
Aug 3, 2019
Test build #108605 has finished for PR 25347 at commit
|
There was a problem hiding this comment.
+1 for me, cc @cloud-fan for a double-check.
How about link this comment from you and Wenchen to the PR description?
mgaido91
commented
Aug 4, 2019
thanks for the suggestion @xuanyuanking , I added the link! |
SparkQA
commented
Aug 4, 2019
Test build #108620 has finished for PR 25347 at commit
|
kiszk
commented
Aug 4, 2019
Do we need similar handing for |
mgaido91
commented
Aug 4, 2019
@kiszk no, since the buffer value for average is a double for longs, so there is not the same issue. |
maropu
commented
Aug 5, 2019
Is this common handling for long sum in DBMSs? In postgresql and mysql, it seems that the output type is decimal and the answer is correct; |
mgaido91
commented
Aug 6, 2019
Yes @maropu, you're right. The reason why I didn't change the output attribute was not to cause a breaking change. But since we are introducing a flag for it, it may be ok to do so. What do you think? cc @cloud-fan what do you think about this? |
maropu
commented
Aug 7, 2019
Yea, I think so. If we have a new flag, IMO it'd be better that spark has the same behivour with the others. |
SparkQA
commented
Aug 8, 2019
Test build #108807 has finished for PR 25347 at commit
|
cloud-fan
commented
Aug 19, 2019
@maropu good point. I think it's more than overflow now. Maybe we should create a config to specify the dialect, and provide 2 options: legacy and ansi. For ansi dialect, we try out best to make the behavior of Spark be consistent with ansi sql standard, including parser, overflow, sum data type, etc. |
mgaido91
commented
Aug 19, 2019
thanks for your comments @cloud-fan and @maropu. I agree long term to have coarser flags controlling all these things, like: ansi strict, legacy and so on. So far we are creating a new flag for each case as it is done now in this PR. I am not sure if your comments say that we should hold this until we create such flags or we can go ahead on this as it is and create those flags later. May you please clarify? Thanks. |
cloud-fan
commented
Aug 19, 2019
We can create the coarser flag later. For this PR, in general LGTM, but let's make the story about sum completed. Is it true that, in the mainstream databases, sum of long returns decimal and sum of other integral types return long? Or do they always return decimal for sum? |
mgaido91
commented
Aug 20, 2019
Well, actually mainstream DBs behave differently among each other:
|
maropu
commented
Aug 20, 2019
SQLServer throws an exception when results overflowed? |
wangyum
commented
Aug 21, 2019
PostgreSQL: postgres=# create table t1(c1 bigint);
CREATE TABLE
postgres=# insert into t1 values(9223372036854775807), (9223372036854775807);
INSERT 02
postgres=# select sum(c1) from t1;
sum
----------------------18446744073709551614
(1 row)db2: [db2inst1@2f3c821d36b7 ~]$ db2 "create table t1(c1 bigint)"
DB20000I The SQL command completed successfully.
[db2inst1@2f3c821d36b7 ~]$ db2 "insert into t1 values(9223372036854775807), (9223372036854775807)"
DB20000I The SQL command completed successfully.
[db2inst1@2f3c821d36b7 ~]$ db2 "select sum(c1) from t1"1--------------------
SQL0802N Arithmetic overflow or other arithmetic exception occurred.
SQLSTATE=22003SQL Server:2019-CTP3.0 1> create table t1(c1 bigint)
2> go
1>insert into t1 values(9223372036854775807), (9223372036854775807)
2> go
(2 rows affected)
1>1>selectsum(c1) from t1
2> go
Msg 8115, Level 16, State 2, Server 8c82b3c03354, Line1
Arithmetic overflow error converting expression to data type bigint.Vertica: dbadmin=> create table t1(c1 bigint);
CREATE TABLE
dbadmin=>insert into t1 values(9223372036854775807);
OUTPUT
--------1
(1 row)
dbadmin=>insert into t1 values(9223372036854775807);
OUTPUT
--------1
(1 row)
dbadmin=>selectsum(c1) from t1;
ERROR 4845: Sum() overflowed
HINT: Try sum_float() instead
dbadmin=>select sum_float(c1) from t1;
sum_float
----------------------1.84467440737096e+19
(1 row)Oracle: SQL>-- BIGINT -> NUMBER(19) : https://docs.oracle.com/cd/B19306_01/gateways.102/b14270/apa.htm
SQL> create table t1(c1 NUMBER(19));
Table created.
SQL>insert into t1 values(9223372036854775807);
1 row created.
SQL>insert into t1 values(9223372036854775807);
1 row created.
SQL>selectsum(c1) from t1;
SUM(C1)
----------1.8447E+19
SQL> create table t2 asselectsum(c1) as s from t1;
Table created.
SQL>desc t2;
Name Null? Type
----------------------------------------- -------- ----------------------------
S NUMBER |
Great thanks for the exhaustive survey!! I'm a bit suprised that they have totally different default behaivours.... Oracle truncates the result? |
mgaido91
commented
Aug 21, 2019
thanks @wangyum ! Actually I tried your very same command and Oracle returned the exact result to me. Anyway, I don't think it is relevant here. Oracle uses always DECIMAL, it doesn't really have a LONG datatype... |
cloud-fan
commented
Aug 21, 2019
If different databases have different behaviors, then I don't see a strong reason to change the return type of sum in Spark. How about we only use decimal as sum buffer? |
mgaido91
commented
Aug 21, 2019
I think the reason is to have feature parity with Postgres. Using it as return type too supports also cases which would overflow otherwise. I think, since we are guarding it with a flag, it is fine to return a decimal and have wider support. |
cloud-fan
commented
Aug 21, 2019
We need to be careful when adding configs to control query semantic. We have a lot of such configs now, but most of them are legacy configs. Legacy configs are OK, since they are not mainly for controlling query semantic, but to provide a way to restore the legacy behavior. That said, if there is a strong reason to change the return type of sum from long to decimal, let's go for it and add a legacy config. But seems it's not the case here. Spark needs to follow SQL standard but not Postgres, so making Spark behave the same with Postgres is not a strong reason to me. If the goal is to leverage the ported Postgres tests, I think it's reasonable. But the config should be internal and clearly states that it's only used in the ported Postgres tests. |
mgaido91
commented
Aug 21, 2019
I 100% agree on that. @maropu what do you think? |
maropu
commented
Aug 22, 2019
Yea, the opinion looks reasonable to me, too.
But, I feel a bit uncomfortable to add a new flag only for this sum behaviour change and I personally think most users might not notice this option. The change to support decimal sum buffer itself looks nice to me, but I think we'd like a coarser flag for that. |
mgaido91
commented
Aug 22, 2019
@maropu@cloud-fan any suggestion on what this flag should be/look like? Meanwhile I'll update the PR to limit the scope only to the buffer, thanks! |
This reverts commit 5738511.
SparkQA
commented
Aug 22, 2019
Test build #109565 has finished for PR 25347 at commit
|
SparkQA
commented
Aug 22, 2019
Test build #109573 has finished for PR 25347 at commit
|
SparkQA
commented
Aug 22, 2019
Test build #109585 has finished for PR 25347 at commit
|
cloud-fan
commented
Aug 26, 2019
@mgaido91 can you do a simple microbenchmark? If the performance overhead is not significant, we can use decimal as sum buffer and provide a legacy config to use long as buffer. |
mgaido91
commented
Aug 26, 2019
I'll do that @cloud-fan , thanks |
@cloud-fan unfortunately the performance overhead is very significant. I tried and run the benchmarks in both modes. Here you can see the code: and here it is the output (as you can see, the overhead is more than 10x on a simple sum of longs): |
cloud-fan
commented
Aug 28, 2019
Now I'm wondering if it's worthwhile to sacrifice 10x perf to handle intermedia overflow. It's not about correctness but usability: without this change, queries are more likely to fail with overflow when summing up long values. So it's a tradeoff between usability and performance. Given it's 10x slowdown, I don't think any users would turn it on by default. If they hit overflow exception later, I think they will just cast the data to decimal before sum. That said, I think it's not very useful to have this feature. Anyway, many thanks to @mgaido91 for investigating and providing the perf numbers! |
mgaido91
commented
Aug 28, 2019
yes, I agree the perf issue is very significant. Let me close this one, thank you all for the reviews! |
What changes were proposed in this pull request?
If
spark.sql.arithmeticOperations.failOnOverFlowistruetemporary overflows in sum of long values cause an exception. This is against what other RDBMS do. The root cause is that we use a long attribute to store the intermediate result of a sum of longs: so if there is an intermediate value which is our of the range representable by long, an exception is raised.The PR introduces a flag which allows to control the datatype of the intermediate attribute of sum of long. When the flag is set to
true, intermediate buffer is a decimal, so temporary overflows don't cause any issue. The flag has been introduced on @cloud-fan 's suggestion because as he pointed out, using always a decimal as intermediate buffer would cause a performance regression.How was this patch tested?
Added UT