Разделение Listagg вместо Group By - PullRequest
0 голосов
/ 15 мая 2018

Что является более эффективным из 2, особенно в случае использования Listagg с данными типа varchar?

SELECT department_id AS "Dept.",
       LISTAGG(last_name, '; ') WITHIN GROUP (ORDER BY hire_date) AS "Employees"
  FROM employees
  GROUP BY department_id
  ORDER BY department_id;

OR

SELECT department_id AS "Dept.",
       LISTAGG(last_name, '; ') WITHIN GROUP (ORDER BY hire_date) 
       OVER (PARTITION BY department_id) AS "Employees"
  FROM employees
  ORDER BY department_id;

Для меня, если я не выбираю только 1/2 столбца, я всегда буду использовать разделение, поскольку мне не нужно включать каждый столбец в предложение GROUP BY.

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Оба запроса выполняют одинаковый объем работы, поскольку каждый из них должен выполнить полное сканирование EMPLOYEES, сортируя значения LAST_NAME в пределах DEPARTMENT_ID.

Используя демонстрацию Oracle HRСхема (где EMPLOYEES имеет 107 строк) и инструмент SQL * Plus set autotrace, мы видим, как выполнить 7 последовательных операций получения и 1 сортировку.

SQL> set autotrace traceonly explain statistics

SQL> select department_id as "Dept."
  2       , listagg(last_name, '; ') within group(order by hire_date) as "Employees"
  3  from   employees
  4  group  by department_id
  5  order  by department_id;

12 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 2107619104

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |    11 |   209 |     4  (25)| 00:00:01 |
|   1 |  SORT GROUP BY     |           |    11 |   209 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES |   107 |  2033 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          7  consistent gets
          0  physical reads
          0  redo size
       1605  bytes sent via SQL*Net to client
        608  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
         12  rows processed

SQL> select department_id as "Dept."
  2       , listagg(last_name, '; ') within group(order by hire_date) over(partition by department_id) as "Employees"
  3  from   employees
  4  order  by department_id;

107 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 1919783947

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |   107 |  2033 |     3   (0)| 00:00:01 |
|   1 |  WINDOW SORT       |           |   107 |  2033 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES |   107 |  2033 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          7  consistent gets
          0  physical reads
          0  redo size
       3703  bytes sent via SQL*Net to client
        685  bytes received via SQL*Net from client
          9  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
        107  rows processed

Существует ещесетевая активность для второго запроса, так как он возвращает больше строк.

0 голосов
/ 15 мая 2018

Два запроса дают разные результаты. Использование GROUP BY вернет по одной строке на группу, а использование OVER ( PARTITION BY .. ) вернет все строки и продублирует результат LISTAGG для каждой строки в разделе.

Используйте любое решение, которое больше подходит для желаемого результата, но они не эквивалентны.

SQL Fiddle

Настройка схемы Oracle 11g R2 :

CREATE TABLE employees ( department_id, last_name, hire_date ) AS
SELECT 1, 'AAA', DATE '2018-01-01' FROM DUAL UNION ALL
SELECT 1, 'BBB', DATE '2018-01-02' FROM DUAL UNION ALL
SELECT 1, 'CCC', DATE '2018-01-03' FROM DUAL UNION ALL
SELECT 2, 'DDD', DATE '2018-01-01' FROM DUAL UNION ALL
SELECT 2, 'EEE', DATE '2018-01-02' FROM DUAL;

Запрос 1 :

SELECT department_id AS "Dept.",
       LISTAGG(last_name, '; ') WITHIN GROUP (ORDER BY hire_date) AS "Employees"
  FROM employees
  GROUP BY department_id
  ORDER BY department_id

Результаты

| Dept. |     Employees |
|-------|---------------|
|     1 | AAA; BBB; CCC |
|     2 |      DDD; EEE |

Запрос 2 :

SELECT department_id AS "Dept.",
       LISTAGG(last_name, '; ') WITHIN GROUP (ORDER BY hire_date) 
       OVER (PARTITION BY department_id) AS "Employees"
  FROM employees
  ORDER BY department_id

Результаты

| Dept. |     Employees |
|-------|---------------|
|     1 | AAA; BBB; CCC |
|     1 | AAA; BBB; CCC |
|     1 | AAA; BBB; CCC |
|     2 |      DDD; EEE |
|     2 |      DDD; EEE |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...