Предположим, у нас есть таблица эффективности кандидатов
CREATE TABLE IF NOT EXISTS candidates AS
WITH RECURSIVE candidates(team, score) AS (
SELECT RANDOM() % 1000, RANDOM() % 1000000
UNION
SELECT RANDOM() % 1000, RANDOM() % 1000000
FROM candidates
LIMIT 1000000
)
SELECT team, score
FROM candidates;
Наша цель - вывести список из 1000 команд и общий балл кандидатов в этой команде. Однако, если общий счет команды не в первом тайме, он будет заменен на ноль. Я придумал два способа сделать это:
- С
EXISTS
потребовалось Run Time: real 30.653 user 30.635649 sys 0.008798
WITH top_teams_verbose(top_team, total_score) AS (
SELECT team, SUM(score)
FROM candidates
GROUP BY team
ORDER BY 2 DESC
LIMIT 500
)
SELECT team, SUM(score) * EXISTS(SELECT 1 FROM top_teams_verbose WHERE team = top_team)
FROM candidates
GROUP BY team;
план запроса
QUERY PLAN
|--SCAN TABLE candidates
|--USE TEMP B-TREE FOR GROUP BY
`--CORRELATED SCALAR SUBQUERY 2
|--CO-ROUTINE 1
| |--SCAN TABLE candidates
| |--USE TEMP B-TREE FOR GROUP BY
| `--USE TEMP B-TREE FOR ORDER BY
`--SCAN SUBQUERY 1
С
IN
потребовалось
Run Time: real 0.045 user 0.041872 sys 0.002999
WITH top_teams_verbose(top_team, total_score) AS (
SELECT team, SUM(score)
FROM candidates
GROUP BY team
ORDER BY 2 DESC
LIMIT 500
),
top_teams AS (
SELECT top_team
FROM top_teams_verbose
)
SELECT team, SUM(score) * (team IN top_teams)
FROM candidates
GROUP BY team;
План запроса
QUERY PLAN
|--SCAN TABLE candidates
|--USE TEMP B-TREE FOR GROUP BY
`--LIST SUBQUERY 3
|--CO-ROUTINE 1
| |--SCAN TABLE candidates
| |--USE TEMP B-TREE FOR GROUP BY
| `--USE TEMP B-TREE FOR ORDER BY
`--SCAN SUBQUERY 1
Почему? Может быть, EXISTS
выполняется для каждой строки, а IN
используется как агрегатная функция? Я взглянул на план запроса, и единственная разница (CORRELATED SCALAR SUBQUERY
против LIST SUBQUERY
) слишком абстрактна, чтобы быть информативной.
Я использую версию SQLite3 3.31.1 2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837bb4d6
На RHEL 7.