Analytic Functions: Better Performance Extended Functionality

Details

Detail name Value
Changelog Number 7458
Type New Feature
Status Resolved
Fix Versions Exasol 6.2.0, Exasol 6.2.dev3
Resolution Date 2019-02-08

Exasol 6.2 contains a completely overhauled analytic function framework.
The new framework speeds up the execution of analytic functions and includes all analytic function features defined by the SQL 2016 Standard.

 Please consider the changed behavior that accompanies these improvements and extensions (section Changed Behaviour)

Main performance improvements

  • Faster execution of analytic functions with ORDER BY in the OVER clause.
  • Faster execution of queries with several analytic functions.
  • Faster execution of complex analytic functions like REGR_INTERCEPT.

New Features

  • Besides ROWS, the new version supports the additional window frame units RANGE and GROUPS. For example:
SELECT MAX(salary) OVER (PARTITION BY dep ORDER BY startdate
    ROWS UNBOUNDED PRECEDING) FROM dataset;

SELECT MAX(salary) OVER (PARTITION BY dep ORDER BY startdate
    RANGE UNBOUNDED PRECEDING) FROM dataset;

SELECT MAX(salary) OVER (PARTITION BY dep ORDER BY startdate
    GROUPS UNBOUNDED PRECEDING) FROM dataset;
  • The new version supports the two previously missing window boundaries <value> PRECEDING and <value> FOLLOWING. This allows the computation of sliding windows in Exasol and extends the number of possible window frame configurations from previously 4 to 13:
  • The new version supports all exclude clauses of the SQL 2016 Standard:
  • UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  • UNBOUNDED PRECEDING AND CURRENT ROW
  • CURRENT ROW AND CURRENT ROW
  • CURRENT ROW AND UNBOUNDED FOLLOWING
  • UNBOUNDED PRECEDING AND <value> PRECEDING
  • UNBOUNDED PRECEDING AND <value> FOLLOWING
  • <value> PRECEDING AND <value> PRECEDING
  • <value> PRECEDING AND CURRENT ROW
  • <value> PRECEDING AND <value> FOLLOWING
  • <value> PRECEDING AND UNBOUNDED FOLLOWING
  • CURRENT ROW AND <value> FOLLOWING
  • <value> FOLLOWING and <value> FOLLOWING
  • <value> FOLLOWING and UNBOUNDED FOLLOWING
SELECT MAX(salary) OVER (PARTITION BY dep ORDER BY startdate
    RANGE UNBOUNDED PRECEDING EXCLUDE CURRENT ROW) FROM dataset;

SELECT MAX(salary) OVER (PARTITION BY dep ORDER BY startdate
    RANGE UNBOUNDED PRECEDING EXCLUDE TIES) FROM dataset;

SELECT MAX(salary) OVER (PARTITION BY dep ORDER BY startdate
    RANGE UNBOUNDED PRECEDING EXCLUDE GROUP) FROM dataset;
  • The new version supports named windows to allow compact queries with better readability:
SELECT MIN(salary) OVER (w), MAX(salary) OVER (w) FROM dataset
    WINDOW w as (PARTITION BY dep ORDER BY startdate RANGE UNBOUNDED PRECEDING);
  • The new version supports eight additional analytic functions:
  • The new version supports the IGNORE NULLS option for the following functions:
  • The new version supports implicit casts of arguments for analytic functions.
  • ANY
  • CUME_DIST
  • EVERY
  • LISTAGG
  • NTH_VALUE
  • NTILE
  • PERCENT_RANK
  • SOME (alias for ANY)
  • FIRST_VALUE
  • LAG
  • LAST_VALUE
  • LEAD
  • NTH_VALUE

Changed Behavior

  • Two new reserved keywords:
  • GROUPS
  • LISTAGG
  • Analytic functions no longer automatically sort the result set. Example:
CREATE OR REPLACE TABLE dataset(id int, dep varchar(100), startdate timestamp, salary double);
INSERT INTO dataset VALUES(3,'A', '2018-03-01', 6500);
INSERT INTO dataset VALUES(2,'A', '2018-02-01', 5500);
INSERT INTO dataset VALUES(1,'A', '2018-01-01', 4500);

SELECT id, SUM(salary) OVER (PARTITION BY dep ORDER BY startdate 
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) from dataset;

Up to 6.1.x the result has been:

ID  SUM(salary) OVER
--  -----------------
 1               4500
 2              10000
 3              16500

Starting from 6.2.0 the result is:

ID  SUM(salary) OVER
--  -----------------
 3              16500
 2              10000
 1               4500
  • Exasol uses a new default window frame for ordered analytic functions. This changes the results for analytic function computations with non-unique orders. Example:
CREATE OR REPLACE TABLE dataset2(id int, dep varchar(100), startdate timestamp, salary double);
INSERT INTO dataset2 VALUES(1,'B', '2019-01-01', 4000);
INSERT INTO dataset2 VALUES(2,'B', '2019-01-01', 5000);
INSERT INTO dataset2 VALUES(3,'B', '2019-01-03', 6000);

-- Ordered analytic function with default window:
SELECT id, SUM(salary) OVER (PARTITION BY dep ORDER BY startdate) from dataset2 ORDER BY startdate;

-- Up to 6.1.x this has been equivalent to:
SELECT id, SUM(salary) OVER (PARTITION BY dep ORDER BY startdate
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) from dataset2 ORDER BY startdate;

-- Starting from 6.2.0 and according to the SQL 2016 standard this is equivalent to:
SELECT id, SUM(salary) OVER (PARTITION BY dep ORDER BY startdate
    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) from dataset2 ORDER BY startdate;

If the ordering is not deterministic due to duplicate values in the ordering columns, then the result of the analytic functions is undefined. Therefore, it is implementation dependent. The result may vary across subsequent executions of the same query.
For the provided example data this leads to the following possible results in 6.1 (depending on the data distribution):

1. Variant:
ID  SUM(salary) OVER
--  -----------------
 1               4000
 2               9000
 3              15000
2. Variant:
ID  SUM(salary) OVER
--  -----------------
 2               5000
 1               9000
 3              15000

In 6.2 the query with default window frame leads to identical results for rows with identical order values regardless of the data distribution. Thus, with respect to the missing ordering, the result in 6.2 is:

ID  SUM(salary) OVER
--  -----------------
 1               9000
 2               9000
 3              15000

It is not possible to recreate the old behavior even with the use of the window frame ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW in 6.2 due to varying data distribution.
For example:

SELECT id, SUM(salary) OVER (PARTITION BY dep ORDER BY startdate
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) from dataset2 ORDER BY startdate;

This query produces 4 different variants in 6.2.

1. Variant:
ID  SUM(salary) OVER
--  -----------------
 1               4000
 2               9000
 3              15000

2. Variant:
ID  SUM(salary) OVER
--  -----------------
 2               5000
 1               9000
 3              15000

3. Variant:
ID  SUM(salary) OVER
--  -----------------
 1               9000
 2               5000
 3              15000

4. Variant:
ID  SUM(salary) OVER
--  -----------------
 2               9000
 1               4000
 3              15000

Changed behavior

Two new reserved keywords (GROUPS, LISTAGG). Exasol no longer automatically sorts results of queries with analytic functions. The new default window frame for ordered analytic functions is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.