Я использую Spark SQL для выполнения простого запроса из моей таблицы Iceberg. Некоторая информация о самой таблице, потому что это может быть полезно (укажите с момента публикации этого вопроса):
Код:
Long start = System.nanoTime();
SparkSession spark = getSparkSession();
System.out.println("Session creation took (ms): " + (System.nanoTime() - start) / 1000000);
Dataset<Row> data = spark.sql("SELECT * FROM myschema.mytable WHERE time BETWEEN CAST('2024-07-10 14:00:00.0' AS TIMESTAMP) AND CAST('2024-07-10 15:40:00.0' AS TIMESTAMP)");
System.out.println("Count: " + data.count());
System.out.println("Partitions: " + data.rdd().getNumPartitions());
System.out.println("Execution took (ms): " + (System.nanoTime() - start) / 1000000);
spark.stop();
Выход:
Создание сессии заняло (мс): 4333
Количество: 0
Разделов: 143
Выполнение заняло (мс): 107029
Важное примечание: количество разделов увеличивается, когда я загружаю все больше и больше данных в исходную таблицу. Если я выполню тот же запрос через некоторое время, счетчик останется равным 0, но количество разделов будет больше.
Два больших вопроса:
1. Почему этот простой запрос выполняется так медленно (около 100 секунд), даже если я намеренно извлекаю 0 строк из исходной таблицы, указывая на временные метки из будущего? Когда я выполняю этот запрос через Trino, это занимает 1-2 секунды. Также, когда я устанавливаю правильные временные метки и извлекаю, например. 500 строк не имеет значения, все равно выполняется ~ 100 секунд.
2. Что это за количество разделов и почему оно постоянно увеличивается? Почему это, например? 143, если в таблице 28 разделов?
ОБНОВЛЕНИЕ (10.07.2024):
Когда я меняю свой запрос на простой «SELECT * FROM myschema.mytable», он выполняется примерно в 10-12 раз быстрее.
Рассмотрите возможность удаления следующих двух журналов и снова измерьте время выполнения.
data.count() — очень дорогая операция в мире искр.
Еще одно замечание: когда я удаляю предложение WHERE из своего запроса и оставляю простой «SELECT * FROM myschema.mytable», он выполняется примерно в 10-12 раз быстрее и возвращает счетчик 11 КБ.
Оказалось, что у Spark по какой-то причине возникла проблема с моим оператором «SELECT...», в то время как я сосредоточился в основном на исправлении разделения.
Я отформатировал время следующим образом: «гггг-ММ-дд ЧЧ:мм:сс» и заменил «spark.sql(...)» на:
spark.read().format("iceberg").load(getSourceTable()).filter(col("time").between(startTime, endTime));
После этого все работает как положено.
Хорошо, но Spark также выполняет код лениво, верно? Это означает, что он ничего не сделает, если я не выполню действие над набором данных после выполнения моего запроса. Итак, я думаю, мне нужно вызвать count(), show() или что-нибудь еще, чтобы даже вызвать этот оператор SELECT. Я попробовал и count(), и show(), и сегодня выполнение этого кода занимает около 180 секунд, и Spark печатает 314 разделов (я также пробовал закомментировать печать количества разделов, но это ничего не меняет).