Оптимизатор на основе затрат
В Spark SQL доступен оптимизатор на основе затрат, с помощью которого можно улучшить планы запросов. Это особенно полезно для запросов с несколькими объединениями. Чтобы оптимизатор работал должным образом, важно получать статистику таблиц и столбцов и регулярно обновлять ее.
Сбор статистики
Чтобы воспользоваться всеми преимуществами оптимизатора, нужно собирать статистику столбцов и статистику таблицы. Вы можете использовать ANALYZE TABLE
команду для сбора статистики вручную.
Совет
Чтобы сохранить статистику в актуальном состоянии, запуститесь ANALYZE TABLE
после записи в таблицу.
Использование ANALYZE
Внимание
Прогнозная оптимизация с ANALYZE
общедоступной предварительной версией. Она включает интеллектуальную коллекцию статистики во время записи. Используйте эту форму для регистрации в общедоступной предварительной версии.
Прогнозная оптимизация автоматически выполняется ANALYZE
, команда для сбора статистики в управляемых таблицах каталога Unity. Databricks рекомендует включить прогнозную оптимизацию для всех управляемых таблиц каталога Unity, чтобы упростить обслуживание данных и сократить затраты на хранение. См. раздел ANALYZE TABLE.
Проверка планов запросов
Проверить план запроса можно несколькими способами.
Команда EXPLAIN
Чтобы проверить, использует ли план статистику, выполните команду SQL:
- EXPLAIN для Databricks Runtime 7.x и более поздних версий;
Если статистика отсутствует, то план запроса может быть неоптимальным.
== Optimized Logical Plan ==
Aggregate [s_store_sk], [s_store_sk, count(1) AS count(1)L], Statistics(sizeInBytes=20.0 B, rowCount=1, hints=none)
+- Project [s_store_sk], Statistics(sizeInBytes=18.5 MB, rowCount=1.62E+6, hints=none)
+- Join Inner, (d_date_sk = ss_sold_date_sk), Statistics(sizeInBytes=30.8 MB, rowCount=1.62E+6, hints=none)
:- Project [ss_sold_date_sk, s_store_sk], Statistics(sizeInBytes=39.1 GB, rowCount=2.63E+9, hints=none)
: +- Join Inner, (s_store_sk = ss_store_sk), Statistics(sizeInBytes=48.9 GB, rowCount=2.63E+9, hints=none)
: :- Project [ss_store_sk, ss_sold_date_sk], Statistics(sizeInBytes=39.1 GB, rowCount=2.63E+9, hints=none)
: : +- Filter (isnotnull(ss_store_sk) && isnotnull(ss_sold_date_sk)), Statistics(sizeInBytes=39.1 GB, rowCount=2.63E+9, hints=none)
: : +- Relation[ss_store_sk,ss_sold_date_sk] parquet, Statistics(sizeInBytes=134.6 GB, rowCount=2.88E+9, hints=none)
: +- Project [s_store_sk], Statistics(sizeInBytes=11.7 KB, rowCount=1.00E+3, hints=none)
: +- Filter isnotnull(s_store_sk), Statistics(sizeInBytes=11.7 KB, rowCount=1.00E+3, hints=none)
: +- Relation[s_store_sk] parquet, Statistics(sizeInBytes=88.0 KB, rowCount=1.00E+3, hints=none)
+- Project [d_date_sk], Statistics(sizeInBytes=12.0 B, rowCount=1, hints=none)
+- Filter ((((isnotnull(d_year) && isnotnull(d_date)) && (d_year = 2000)) && (d_date = 2000-12-31)) && isnotnull(d_date_sk)), Statistics(sizeInBytes=38.0 B, rowCount=1, hints=none)
+- Relation[d_date_sk,d_date,d_year] parquet, Statistics(sizeInBytes=1786.7 KB, rowCount=7.30E+4, hints=none)
Внимание
Параметр статистики rowCount
особенно важен для запросов с несколькими объединениями. Если rowCount
отсутствует, значит у вас недостаточно данных для его вычисления (т. е. нет статистики по некоторым необходимым столбцам).
Пользовательский интерфейс Spark SQL
На странице пользовательского интерфейса Spark SQL можно просмотреть выполненный план и точность статистики.
Например, строка rows output: 2,451,005 est: N/A
означает, что этот оператор выдал приблизительно 2 млн строк, а статистика для него недоступна.
Строка rows output: 2,451,005 est: 1616404 (1X)
означает, что оператор вернул около 2 млн строк, прогнозируемое значение для него было 1,6 млн, а коэффициент ошибки прогноза равен 1.
Строка rows output: 2,451,005 est: 2626656323
означает, что оператор вернул около 2 млн строк, прогнозируемое значение для него было 2 млрд, а коэффициент ошибки прогноза равен 1000.
Отключение оптимизатора на основе затрат
Оптимизатор включен по умолчанию. Чтобы отключить его, измените флаг spark.sql.cbo.enabled
.
spark.conf.set("spark.sql.cbo.enabled", false)