Buffl

Собеседование

DA
von David A.

Кластеризованный индекс VS индекс

Кластеризованный индекс — это индекс, который сортирует строки с данными в таблице. Он хранит данные в листьях индекса, где все значения отсортированы в определённом порядке — либо по возрастанию, либо по убыванию. Благодаря этому существенно возрастает скорость поиска данных (при условии последовательного доступа к данным). В таблице может присутствовать только один кластеризованный индекс.

Некластеризованный индекс — индекс, который используется для применения индексов к неключевым столбцам. Главное отличие от кластеризованного индекса заключается в том, что некластеризованный индекс не упорядочивает данные физически. Он хранит данные и индексы в разных местах. Листья некластеризованного индекса содержат только те столбцы таблицы, по которым определён данный индекс. Это означает, что системе запросов необходима дополнительная операция для извлечения требуемых данных. Некластеризованные индексы нельзя отсортировать, в отличие от кластеризованных, однако существует возможность создания более одного некластеризованного индекса.

Методы сканирования данных


Планировщик будет решать какое сканирование использовать для извлечения данных(если индексов нет, то полное, а если есть то он будет думать)

index scan - Если есть большой набор проиндексированных данных и мы осуществляем поиск по индексу и потенциально в результирующий набор попадает малое кол-во строк(например 1), а в таблице содержится 1000000 строк, то оптимизатор включит index scan.

index only scan - Некоторые индексы(не все), хранят вместе с идентификаторами строк сами проиндексированные значения и это позволяет им просто читать сам индекс без обращения к таблицам и забирать результат прямо из самого индекса. Вместо чтения значения из таблиц при таком сканировании необходимо лишь заглянуть в карту видимости, чтобы выяснить актуальность индексных записей. Потому что карта видимости ставит 1, показывая что можно выполнить такое сканирование и данные актуальные

bitmap scan - надо выбрать кол-во строк не так мало как при index scan, но и не так много как при sequential scan. Например 300к из млн

sequential scan - Даже если поиск идёт по индексированному столбцу, а там куча данных и так забирать надо, то планировщик может наплевать и выбрать последовательное сканирование.


Физические виды join


Nested loops join (соединения вложенных циклов)

Вложенные циклы. каждая строка из одной таблицы сравнивается с каждой строкой из другой таблицы и соединяются

Merge join (соединение слиянием)

Самые быстрый. Используется когда 2 большие таблицы. Требует чтобы обе таблицы имели индекс по ключу(т.е отсортированы).

Одна строка сравнивается с другой, когда нет совпадения, то переключается на другую строку, которая сравнивается с этой

Если повторяющиеся значения:

Записывает любые повторяющиеся значения из второй таблицы во временную таблицу и выполняет сравнения там. Затем, если эти значения также дублируются в первой таблице, сравнивает их со значениями, которые уже сохранены во временной таблице.

Hash match join (хеш-соединение)

Используется для больших таблиц, когда отсутствуют индексы или когда данные не отсортированы, а условие соединения предполагает точное совпадение

Берем меньшую из таблиц, для каждой строки создаем запись в хэш-таблице. Затем берем большую, сканируем и проверяем каждую строку на совпадение с хэш-таблицей, если совпадают, то соединяем

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


У тебя есть 100 миллионов строк и тебе необходимо удалить 90 миллионов, как ты это сделаешь и почему?

Проверка на понимание работы БД. Пример с постгресом, таблицы хранятся как heap(куча). Есть сегмент = 1 ГБ, который внутри состоит из страниц данных, вроде 1 стр = 8 Кб. Есть определенный заголовок версии строки и сама строка данных. Надо понимать, если мы хотим 90 миллионов просто удалить, например пишем DELETE FROM .. TABLE WHERE id > 10.. То физически они не удалятся из этой таблицы. В заголовке строки есть 2 параметра типо xmin и xmax. в xmin ставится номер транзакции когда данная строка обновлена или удалена или что-то ещё. А в xmax ставится дата окончания, когда эту строку либо обновили, либо удалили. То есть номер транзакции которая удалила эту строчку. Мы просто в эти 90 миллионов ставим xmax(Номер транзакции которая удалила эту строку). Соответственно это долго. Есть пример 2х способов(на самом деле их больше)

В основе хотят услышать, что мы должны не просто в тупую удалять строки через DELETE, а именно удалить саму таблицу, потому что DROP TABLE и TRUNCATE TABLE работаю так, что они удаляют таблицу.

TRUNCATE(запоминает структуру таблицы, удаляет сегментный файл, а потом пересоздает его, DDL, но индексы и статистику не обновляет)

DROP(удаляет всё и строки и статистику и индексы)

Снизу 2 способа.


Как выполняется работа приложения в спарке (workflow) ? (Когда выделяется память, когда отдаются ресурсы)


Workflow приложения в Spark:

  1. Приложение запускается и инициализирует SparkContext.

  2. Программа-драйвер запрашивает у менеджера кластеров ресурсы для запуска исполнителей.

  3. Менеджер кластеров запускает исполнителей.

  4. Драйвер запускает код Spark.

  5. Исполнители запускают задания и отправляют результаты драйверу.

  6. SparkContext останавливается, а исполнители закрываются и возвращают ресурсы обратно в кластер.

Выделение ресурсов в Spark может происходить двумя способами:

  1. Статическое выделение. Объём памяти и количество ядер выделяют на этапе запуска приложения и оставляют неизменными в течение всего выполнения. Подходит для задач, в которых требуется предсказуемое и стабильное распределение ресурсов на протяжении всего выполнения.

  2. Динамическое выделение. Система автоматически адаптирует объём памяти и количество ядер исполнителей, чтобы удовлетворить текущим потребностям приложения. Этот метод позволяет управлять ресурсами в режиме реального времени, что делает его подходящим для приложений с переменной нагрузкой.

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

Что такое rdd, dataset и dataframe? Как rdd работает "под капотом"?

RDD (Resilient Distributed Dataset) — это неизменяемая распределённая совокупность элементов данных, которые могут храниться в памяти или на диске в кластере машин. RDD позволяют совершать низкоуровневые трансформации над неструктурированными данными (как медиа или текст).

DataFrame — это распределённая коллекция данных, организованная в именованные столбцы. Концептуально он соответствует таблице в реляционной базе данных с оптимизацией для распределённых вычислений.

Dataset — это расширение API DataFrame, обеспечивающее функциональность объектно ориентированного подхода, производительность оптимизатора запросов Catalyst и механизм хранения вне кучи.

RDD работают «под капотом» путём разделения данных на несколько разделов (Partition), которые хранятся на каждом узле-исполнителе. Каждый узел выполняет работу только на собственных разделах. RDD отказоустойчивы, так как отслеживают поток данных для автоматического восстановления потерянных данных в случае сбоя. 

Джоба работала 7 дней, потом упала, заказчик не получил результат. В чем проблема и где начать смотреть?

Возможные причины проблемы:

1. Ошибка в коде:

Непредвиденная ошибка в логике программы

Проблема с обработкой данных или выходными данными

2. Отсутствие ресурсов:

Выделение недостаточных ресурсов для выполнения задачи

Перегрузка кластера Hadoop

3. Проблемы с конфигурацией:

Неправильная настройка параметров Spark или Hadoop

Конфликт между версиями компонентов

4. Сбой инфраструктуры:

Проблемы с сетевым соединением

Сбой узлов кластера

5. Проблемы с мониторингом:

Отсутствие эффективного мониторинга процесса

Неисправность системы мониторинга


Где начать поиск:

1. Логи:

Проверьте логи джобы и кластера

Используйте команды:`cat /path/to/job/logs/`* `tail -f /path/to/job/logs/latest.log`

2. Метрики производительности:

Проверьте метрики CPU, памяти и дискового пространства

Используйте инструменты мониторинга, такие как Nagios или Prometheus

3. Статус задачи:

Проверьте статус задачи через интерфейс управления задачами (например, YARN UI)Используйте команду:

`yarn application -list`4. Результаты выполнения:

Проверьте директорию с результатами выполнения

Используйте команду:

`hadoop fs -ls /path/to/results/directory`

5. Мониторинг ресурсов:

Проверьте использование ресурсов кластера

Используйте команду:* `yarn cluster-info`

Можно ли совмещать использование GROUP BY и оконных функций? Как это сделать?

Совмещать использование GROUP BY и оконных функций в SQL можно, но с определёнными ограничениями.

В соответствии с порядком логической обработки запросов, оконные функции обрабатываются на этапе SELECT или ORDER BY, то есть после GROUP BY. Поэтому при оценке GROUP BY оконные функции ещё не вычислены.

Один из способов совместить эти понятия — использовать подзапрос. В нём вычислить оконную функцию, а затем использовать её в основном запросе. Например:

SELECT quartile, min(points), max(points), count(*) FROM (SELECT ntile(4) OVER (ORDER BY points) AS quartile, points FROM midterm) groups GROUP BY quartile

В подзапросе используется функция NTILE() для разделения студентов на группы, а в основном запросе вычисляется статистика: минимум, максимум и количество студентов.

Ещё одна возможность — использовать общее табличное выражение (CTE). Его можно определить на основе запроса, вычисляющего групповой агрегат, а во внешнем запросе вычислить оконный агрегат.

Что такое колоночная база данных, в чем ее преимущества и недостатки?

Колоночная база данных — это система управления базами данных, которая хранит данные столбцами, а не строками, как в традиционных реляционных базах данных.

Преимущества колоночных баз данных:

  • Ускорение аналитических запросов. При агрегациях и фильтрациях задействуются только те столбцы, которые участвуют в запросе. При этом данные одного типа лежат последовательно.

  • Эффективное сжатие данных. Данные в одном столбце имеют схожую природу, что позволяет применять более эффективные алгоритмы сжатия.

  • Снижение нагрузки на I/O. Извлечение только нужных столбцов уменьшает объём операций ввода-вывода.

Недостатки колоночных баз данных:

  • Меньшая эффективность для транзакционных операций. Записи и обновления, которые влияют на большое количество столбцов, требуют больше операций, чем в реляционных базах.

  • Усложнение работы с несжатыми или разреженными данными. Если данные столбца не поддаются сжатию или содержат много пропусков, преимущества колоночного подхода снижаются.


Self(что это, для чего нужен, как и где использовать)

Self в Python — это ссылка на текущий экземпляр класса. Через self можно получить доступ к атрибутам и методам класса внутри него.

Для чего нужен self:

  • Доступ к атрибутам и методам экземпляра. С помощью переменной self методы экземпляра могут легко получить доступ к различным атрибутам и другим методам одного и того же объекта.

  • Изменение состояния экземпляра. Переменная self также способна изменять состояние объекта.

  • Читаемость и понятность кода. Использование self подчёркивает, что метод применяется к конкретному экземпляру класса, что делает код более ясным и понятным.

Как и где использовать self: self является явным параметром для того, чтобы подчеркнуть, что метод применяется к конкретному экземпляру класса. Это делается при определении метода, когда ему первым аргументом передаётся self. Также переменная self может использоваться для доступа к полю переменной внутри определения класса.

Как рассчитывается сложность алгоритма? на примере list, tuple

Сложность алгоритма рассчитывается с использованием верхней (наихудшей) оценки, которая выражается с использованием нотации O.

Выделяют следующие основные категории алгоритмической сложности в O-нотации:

  • Постоянное время: O(1). Время выполнения не зависит от количества элементов во входном наборе данных. Пример: операции присваивания, сложения, взятия элемента списка по индексу и др..

  • Линейное время: O(N). Время выполнения пропорционально количеству элементов в коллекции. Пример: найти имя в телефонной книге простым перелистыванием, почистить ковёр пылесосом и т.д..

Пример расчёта сложности алгоритма на примере списка: если len(alist) — это N, тогда цикл for i in range(len(alist)) будет иметь сложность O(N), так как цикл выполняется N раз.

Ещё один пример: итоговая сложность двух вложенных действий равна произведению их сложностей. Например, если некоторая функция f(...) имеет класс сложности O(N2), а её выполняют в цикле N раз, то сложность этого кода будет равна: O(N) × O(N2) = O(N×N2) = O(N3).

Что такое итерация?

Итерация в Python — это процесс обхода элементов итерируемого объекта. То есть это процедура взятия элементов чего-то по очереди. В более общем смысле — последовательность инструкций, которая повторяется определённое количество раз или до выполнения указанного условия.

Итерируемый объект в Python — это любой объект, от которого можно получить итератор. Такими объектами являются, например, списки, кортежи, строки и словари. Итерируемыми объектами могут быть и пользовательские объекты, если в их классе реализован специальный метод iter().

Итератор в Python — это объект, который реализует метод next(), возвращающий следующий элемент итерируемого объекта при каждом вызове, и бросающий исключение StopIteration, когда элементы закончились. Итератор получают с помощью функции iter().

Пример итерации:

numbers = [1, 2, 3, 4, 5]

for num in numbers:

print(num)

Что такое spill в Spark?


Spill в Spark — это термин для обозначения процесса перемещения данных из памяти на диск, а затем снова обратно в память.

Он происходит, когда данных слишком много, и они не помещаются в выделенный для задачи раздел памяти. Фреймворк вынужден выполнять дорогостоящие операции чтения и записи на диск, чтобы освободить локальную оперативную память и избежать ошибки нехватки памяти (OutOfMemory, OOM), которая может привести к сбою приложения.

Некоторые причины spill-эффекта в Spark:

  • Большое значение параметра spark.sql.files.maxPartitionBytes. По умолчанию это количество байтов для упаковки в один раздел при чтении файлов формата Parquet, JSON и ORC. Если установить раздел, считываемый Spark намного больше, например, 1 ГБ, активное поглощение может вызвать spill-эффект.

  • Операция explode() на небольшом массиве данных с соединениями и декартовыми соединениями (CrossJoin) двух таблиц, результат которого может превысить размер раздела.

  • Агрегации по искажённым данным, которые неравномерно распределены по узлам кластера, также потенциально могут создать очень большой раздел и вызвать перенос данных из памяти на диск и обратно.


Параллелизм в Apache Spark

Параллелизм в Apache Spark — это способность выполнять несколько задач одновременно на кластере. Spark использует модель параллелизма на уровне операций, что означает, что каждая операция в коде может быть выполнена параллельно на разных узлах кластера.

Уровень параллелизма определяет, сколько задач будет выполнено одновременно на кластере. Это может быть настроено через параметры конфигурации Spark. Важно подобрать подходящее значение в зависимости от характеристик кластера и характера обрабатываемых данных.

По умолчанию значение уровня параллелизма (spark.default.parallelism) равно общему количеству ядер на кластере.

Также в Spark есть параллелизм второго порядка, который позволяет выполнять несколько действий параллельно. Например, когда исполнители завершат первое действие, они немедленно начнут работу над вторым и не будут бездействовать, пока оба не будут завершены.

Расскажи порядок разрешения методов? python

Порядок разрешения методов (Method Resolution Order, MRO) в Python определяет последовательность, в которой Python ищет методы и атрибуты в иерархии классов. Это особенно важно при работе с множественным наследованием, когда класс может наследовать атрибуты и методы от нескольких родительских классов.

Алгоритм C3-линеаризации определяет MRO путём комбинирования:

  1. Самого класса. Всегда начинаем с самого класса, в котором вызван метод

  2. Списка родительских классов в порядке их перечисления. После текущего класса проверяем базовые классы в том порядке, в каком они указаны при наследовании.

  3. MRO родительских классов в том же порядке. Если один и тот же базовый класс наследуется через несколько путей, он проверяется только один раз и в правильном порядке (все остальные разы он будет пропущен).

Порядок разрешения методов следует линейной последовательности. Это означает, что Python ищет метод от дочернего класса к родительскому, следуя порядку, указанному в определении класса.

Проверить порядок обхода методов и полей класса в Python можно, используя атрибут mro или функцию mro().

Как работает память в питоне?


Память в Python работает следующим образом:

  1. При запуске программы операционная система создаёт новый процесс и выделяет под него ресурсы. В эту память загружается интерпретатор Python вместе со всеми необходимыми ему для работы данными, включая код программы.

  2. Программа не сама выполняет сохранение и освобождение памяти. Интерпретатор лишь запрашивает это у диспетчера памяти.

  3. Диспетчер памяти делегирует работу, связанную с хранением данных, аллокаторам — распределителям памяти. Непосредственно с оперативной памятью взаимодействует распределитель сырой памяти. Поверх него работают аллокаторы, реализующие стратегии управления памятью, специфичные для отдельных типов объектов.

  4. Виртуальная память Python представляет иерархическую структуру:

    • Арена — фрагмент памяти, расположенный в пределах непрерывного блока оперативной памяти объёмом 256 Кб. Объекты размером более 256 Кб направляются в стандартный аллокатор C.

    • Пул — блок памяти внутри арены, занимающий 4 Кб, что соответствует одной странице виртуальной памяти.

    • Блок — элемент пула размером от 16 до 512 байт. В пределах пула все блоки имеют одинаковый размер. 

  5. Для освобождения памяти используются два механизма: счётчик ссылок и сборщик мусора. Счётчик ссылок увеличивается на единицу, когда создаётся что-то, что обращается к объекту, например, сохраняется объект в новой переменной. И наоборот, счётчик уменьшается на единицу, когда перестаётся ссылаться на объект. Если содержимое всех переменных — ссылок на объект изменится, счётчик обнулится. В этот момент Python освободит ячейку памяти, и по её адресу можно будет хранить новый объект. 


Какие механизмы выполнения операций соединения в спарке вы знаете?

5 механизмов выполнения операций соединения в Apache Spark SQL

  1. Broadcast Hash Join. Один из входных наборов данных транслируется всем исполнителям. Для транслируемого набора данных создаётся хеш-таблица, после чего каждый раздел не транслируемого входного набора данных присоединяется независимо к другому набору данных, доступному как локальная хеш-таблица.

  2. Shuffle Hash Join. Наборы данных выравниваются по выбранной схеме разделения. Если нужно, выполняется шаффлинг для соответствия схеме разделения. Затем выполняется join в каждой партиции с использованием hash join.

  3. Sort Merge Join. Аналогично shuffle hash join, но требует сортировки данных перед join.

  4. Cartesian Join. Используется только для cross join. Создаёт все возможные пары записей из обоих наборов данных.

  5. Broadcast Nested Loop Join. Является механизмом join по умолчанию, когда нельзя выбрать другие механизмы. 


Что такое Adaptive query execution?


Adaptive Query Execution (AQE) — это механизм оптимизации запросов в Apache Spark в реальном времени. Он динамически оптимизирует планы выполнения запросов на основе статистики и характеристик данных во время выполнения.

AQE позволяет более эффективно использовать ресурсы и снижать время выполнения. Например, он может разделить большие задачи на более мелкие, что уменьшает узкие места.

AQE также позволяет отложить решение о стратегии объединения до времени выполнения, выбрав наиболее подходящий метод на основе фактических размеров данных.

AQE используется в трёх сценариях, где традиционная оптимизация может не работать:

  • Перекос данных. Spark может определить перекос данных во время выполнения и скорректировать выполнение задач.

  • Неизвестные шаблоны объединений. В запросе с неизвестными шаблонами объединений AQE может отложить решение о стратегии объединения до времени выполнения, выбрав наиболее подходящий метод.

  • Изменение характеристик данных. Размер и распределение наборов данных могут меняться, делая статически определённые планы запросов устаревшими.


Author

David A.

Informationen

Zuletzt geändert