Оптимизация производительности в Phoenix
В этой статье приведены рекомендации по оптимизации производительности Phoenix в ADH.
Настройка конфигурации
Соединение
Описанные ниже параметры управляют настройкой подключений в Phoenix.
| Параметр | Значение по умолчанию и описание | Рекомендация | 
|---|---|---|
| phoenix.query.timeoutMs | Значение по умолчанию:  Определяет время, в течение которого запрос может выполняться, прежде чем он будет прерван на стороне клиента. Это предотвращает чрезмерное потребление ресурсов длительными или неконтролируемыми запросами и потенциальное снижение производительности | Установите относительно небольшое значение ( Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.query.threadPoolSize | Значение по умолчанию:  Этот параметр определяет максимальное количество потоков в пуле, выделенных для выполнения входящих запросов Phoenix. Каждый поток обрабатывает один запрос (или часть сложного запроса) | Начните со значения по умолчанию и запустите типичную рабочую нагрузку. Отслеживайте ключевые метрики: 
 Если процессоры загружены недостаточно, задержка запросов высока или глубина очереди запросов постоянно велика, увеличьте параметр на 25%. Если процессоры загружены на максимум, а оперативная память исчерпана, уменьшите параметр на 25%. После каждой корректировки перезапускайте рабочую нагрузку и контролируйте метрики. Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| hbase.client.scanner.timeout.period | Значение по умолчанию:  Этот параметр определяет тайм-аут бездействия сканера, по истечении которого сервер региона закроет его | Начните со значения по умолчанию и запустите типичную рабочую нагрузку.
Проверьте логи на наличие исключений типа  Этот параметр находится в секции hbase-site.xml на конфигурационной странице сервиса HBase | 
| zookeeper.session.timeout | Значение по умолчанию:  Этот параметр определяет тайм-аут для сеансов ZooKeeper. HBase (и, следовательно, Phoenix) использует ZooKeeper для координации. Потеря сеанса ZooKeeper сервером региона может привести к проблемам с подключением и нестабильной работе | В средах с нестабильными сетями или высокой нагрузкой на ZooKeeper рекомендуется увеличить это значение. Однако чем больше значение, тем дольше будет определяться действительно неисправный сервер региона. Не устанавливайте слишком низкое значение, так как временные сбои в сети могут привести к ненужным отключениям. Этот параметр необходимо согласовывать с конфигурацией ZooKeeper. Этот параметр находится в секции hbase-site.xml на конфигурационной странице сервиса HBase | 
Запросы
Описанные ниже параметры связаны с производительностью запросов в Phoenix.
| Параметр | Значение по умолчанию и описание | Рекомендация | 
|---|---|---|
| phoenix.query.spoolThresholdBytes | Значение по умолчанию:  Ограничивает объем памяти, который запрос может использовать для сортировки или группировки результатов, не прибегая к перебросу памяти на диск для временного хранения.
Это критически важный параметр для запросов, использующих предложения  | Установите для этого параметра значение  
 Если какая-либо из этих метрик слишком высокая — удвойте значение параметра, перезапустите рабочую нагрузку и снова отслеживайте метрики. Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.query.maxRows | Значение по умолчанию:  Этот параметр ограничивает максимальное количество строк, которое может вернуть один запрос.
Если запрос попытается вернуть больше строк, чем это ограничение, Phoenix выбросит исключение ( | Начните со значения по умолчанию и запустите типичную рабочую нагрузку.
Отслеживайте выполнение запросов и выявляйте те из них, которые возвращают неожиданно большие наборы результатов или вызывают проблемы с производительностью.
Проверьте логи запросов, чтобы понять типичные размеры наборов результатов для различных типов запросов.
Определите запросы, которые постоянно возвращают очень большое количество строк.
Основываясь на результатах, установите значение параметра, достаточно большое для обработки большинства корректных запросов, но достаточно низкое, чтобы неконтролируемые запросы не перегружали систему.
Установите относительно консервативное значение (например,  Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.query.resultset.cache.enabled | Значение по умолчанию:  Этот параметр определяет, включено ли кеширование результатов запросов на стороне клиента. Если включено, Phoenix будет кешировать результаты запросов, позволяя последующим идентичным запросам возвращать результаты из кеша вместо повторного выполнения на сервере | Включите этот параметр, если у вас часто выполняются запросы с большим объемом чтения и стабильными данными. Это может значительно повысить производительность чтения. Однако это увеличивает потребление клиентской памяти и создает риск устаревания данных, если базовые данные часто меняются, а кеш не аннулируется. Следите за актуальностью клиентской памяти и данных. Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.query.optimizeMaxParallelScans | Значение по умолчанию:  Этот параметр определяет максимальное количество параллельных сканирований, которые Phoenix может инициировать для определенных типов запросов (например, запросов, которые включают несколько параллельных сканирований по разным регионам или таблицам) | Если ваши таблицы распределены по многим регионам или имеется сильно распределенный набор данных, увеличение этого значения может повысить производительность сложных аналитических запросов, которым может помочь параллелизм. Увеличивайте значение с осторожностью, так как слишком большое значение может создать значительную нагрузку на службы метаданных кластера и на сеть. Следите за активностью серверов регионов и ZooKeeper. Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.mutate.batchSize | Значение по умолчанию:  Этот параметр определяет количество операций изменения ( | Увеличьте это значение для повышения пропускной способности записи при выполнении массовой загрузки или массовых обновлений. Начните с удвоения значения по умолчанию и следите за производительностью. Если на стороне клиента или на серверах региона возникает ошибка  Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.mutate.maxSizeBytes | Значение по умолчанию:  Определяет максимальный размер одной партии операций изменения. Это предотвращает перегрузку серверов регионов очень большими партиями | Если вы вставляете строки с очень большими значениями (например, большими двоичными данными), и лимит по умолчанию постоянно превышается, увеличьте это значение. Не устанавливайте слишком большое значение, так как это может привести к проблемам с серверами регионов. При появлении ошибок, связанных с изменениями слишком большого размера, уменьшите это значение. Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| ВНИМАНИЕПоследние два параметра ( phoenix.mutate.batchSizeиphoenix.mutate.maxSizeBytes) работают в связке.
Партия данных будет отправлена при достижении любого из ограничений. | 
JDBC URL
Описанные ниже параметры можно использовать в строке JDBC URL при подключении к Phoenix.
| Параметр | Значение по умолчанию и описание | Рекомендация | 
|---|---|---|
| phoenix.query.client.fetchSize | Значение по умолчанию:  Этот параметр определяет количество строк, которые клиент запрашивает у сервера в каждой операции выборки во время выполнения запроса. Больший размер выборки сокращает количество сетевых циклов, потенциально повышая производительность запросов, возвращающих много строк | Увеличьте значение для запросов, извлекающих большое количество строк, чтобы снизить задержку в сети.
Уменьшите значение, если памяти на клиенте становится недостаточно или при плохих сетевых условиях, которые могут приводить к тайм-ауту при выборке больших объемов данных.
Часто бывает полезно сделать это значение равным значению параметра  | 
| phoenix.statement.prefetchRows | Значение по умолчанию:  Этот параметр задает количество строк, предварительно загружаемых в локальный буфер клиента.
Если установлено значение больше  | Укажите значение больше  | 
| phoenix.schema.isNamespaceMappingEnabled | Значение по умолчанию:  Этот параметр определяет, должен ли Phoenix использовать пространства имен HBase для представления схем Phoenix | Установите этот параметр в значение  | 
| phoenix.use.stats | Значение по умолчанию:  Этот параметр определяет, включено ли использование статистики при планировании запросов | Оставьте это значение равным  | 
| async | Значение по умолчанию:  Этот параметр определяет, включены ли асинхронные запросы. Это позволяет клиенту отправлять запросы и получать результаты позже | Установите этот параметр в значение  | 
Серверы регионов
Описанные ниже параметры относятся к работе серверов регионов в контексте работы Phoenix.
| Параметр | Значение по умолчанию и описание | Рекомендация | 
|---|---|---|
| hbase.rpc.timeout | Значение по умолчанию:  Этот параметр определяет общее время ожидания для RPC-вызовов к серверам регионов HBase. Если клиент не получает ответ от сервера регионов в течение этого времени, RPC-вызов считается неудавшимся. Phoenix использует RPC-вызовы практически для всех операций | При частом появлении ошибок  Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.coprocessor.maxServerCacheBytes | Значение по умолчанию:  Этот параметр определяет размер кеша на стороне сервера для результатов запросов в сопроцессоре на серверах регионов. Это может значительно повысить производительность часто выполняемых запросов с относительно небольшими наборами результатов. Значение определяется в байтах | Если у вас много повторяющихся запросов, начните с небольшого значения (например,  Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
| phoenix.index.builder.threads | Значение по умолчанию:  Этот параметр определяет количество потоков, которые будут использоваться для построения глобальных индексов. Глобальные индексы строятся асинхронно в фоновом режиме, и этот параметр управляет уровнем параллелизма, используемым при построении индексов | Если нужно индексировать большое количество строк и вы хотите ускорить процесс построения индекса, увеличьте это значение до числа доступных ядер ЦП на серверах регионов. Если процесс построения индекса создает слишком большую нагрузку на серверы регионов, уменьшите это значение. Этот параметр нужно добавлять вручную в секции Custom hbase-site.xml на конфигурационной странице сервиса HBase | 
Настройка БД
Ключ строки
Ключ строки — важнейший фактор при планировании БД в HBase и, следовательно, в Phoenix. Правильно устроенный ключ строки может значительно повысить производительность запросов и локальность данных. Неправильно устроенный ключ строки может привести к перегрузкам, медленным запросам и общей неэффективности системы.
Ниже представлен список ключевых факторов при конструировании ключа строки:
- 
Паттерны запросов. Ключ строки следует выбирать в зависимости от того, как вы планируете запрашивать данные. Определите наиболее распространенные и критичные к производительности запросы и спроектируйте ключ строки для их оптимизации. Примите во внимание следующее: - 
Сканирование диапазона. Если вам часто требуется извлекать данные в определенном диапазоне, ключ строки должен включать дату или ее производную в качестве префикса. 
- 
Точечные запросы. Если вам нужно быстро извлекать отдельные строки по уникальному идентификатору, сделайте этот идентификатор ключом строки. 
- 
Запросы на основе префикса. Если вы часто используете запросы, основанные на префиксе определенного атрибута, включите этот атрибут в начало ключа строки. 
 
- 
- 
Hotspotting. Избегайте конструкций ключей строк, которые приводят к hotspotting. Это происходит, когда непропорционально большой объем данных записывается или считывается с одного сервера регионов, создавая узкое место. Распространенные причины: - 
Монотонно возрастающие ключи. Использование временных меток, порядковых номеров или других монотонно возрастающих значений в качестве ключа строки направит все новые операции записи в один регион, что приведет к перегрузке сервера. 
- 
Последовательные ключи. Подобно монотонно возрастающим ключам, последовательные ключи также могут вызывать hotspotting, если они сосредоточены в небольшом диапазоне. 
 
- 
- 
Salting. Это метод избегания hotspotting путем добавления префикса к ключу строки для распределения записи по нескольким регионам. 
- 
Предварительное разделение (pre-splitting). Подразумевает предварительное создание нескольких регионов для более равномерного распределения начальной нагрузки. Это особенно важно для больших наборов данных. 
- 
Длина ключа. Старайтесь использовать как можно более короткие ключи строк, не жертвуя при этом уникальностью или производительностью запросов. Более короткие ключи уменьшают объем хранилища и повышают производительность сканирования. 
- 
Составные ключи. Phoenix поддерживает составные ключи строк, которые объединяют несколько столбцов в один ключ. Это полезно, когда нужно выполнять запросы на основе комбинации атрибутов. - 
Порядок столбцов. Порядок столбцов в составном ключе имеет значение. Размещайте наиболее часто запрашиваемые столбцы в начале. 
- 
Типы данных. Выберите подходящие типы данных для каждого столбца в составном ключе, чтобы оптимизировать дисковое пространство и производительность. 
 
- 
Пример
Рассмотрим таблицу, хранящую данные датчиков, со следующими столбцами:
- 
sensor_id
- 
timestamp
- 
temperature
- 
humidity
Если вы часто запрашиваете данные датчиков в определенном временном диапазоне, можно спроектировать составной ключ строки как комбинацию sensor_id и timestamp.
Однако, если количество датчиков невелико, а запись в определенные временные диапазоны достаточно интенсивна, возникнет проблема hotspotting.
В этом случае вам потребуется добавить к sensor_id несколько salt-регионов.
Семейства столбцов
В HBase и Phoenix данные хранятся в семействах столбцов. Выбор правильного дизайна семейства столбцов имеет решающее значение для оптимизации эффективности хранения, производительности запросов и общей масштабируемости системы.
Ниже приведен список ключевых факторов, которые следует учитывать при дизайне семейства столбцов:
- 
Локальность обращения. Столбцы, к которым часто обращаются одновременно, следует сгруппировать в одно семейство столбцов. Это повышает производительность чтения, поскольку HBase извлекает данные из целых семейств столбцов сразу. И наоборот, столбцы, к которым редко обращаются одновременно, следует помещать в разные семейства. 
- 
Количество семейств столбцов. Минимизируйте количество семейств столбцов в таблице. Каждое семейство столбцов имеет отдельные требования к хранилищу и памяти. Небольшое количество хорошо спроектированных семейств столбцов, как правило, предпочтительнее большого количества фрагментированных семейств. Идеальное количество семейств столбцов — 2 или 3. 
- 
Характеристики хранения. Учитывайте характеристики хранения данных в каждом семействе столбцов: - 
Тип данных. Столбцы со схожими типами данных (например, строковые, числовые, двоичные) можно сгруппировать для оптимизации хранения и сжатия. 
- 
Размер данных. Столбцы, содержащие большие объекты (например, изображения, документы), следует размещать в отдельных семействах столбцов, чтобы избежать влияния на производительность других часто используемых данных. 
 
- 
- 
Эволюция схемы. Семейства столбцов обеспечивают определенную гибкость для эволюции схемы. Вы можете добавлять новые столбцы в существующее семейство столбцов, не влияя на другие семейства. Однако следует учитывать влияние добавления большого количества столбцов в одно семейство, поскольку это может повлиять на производительность. 
- 
Именование семейств столбцов. Выбирайте описательные и содержательные имена для семейств столбцов, но делайте их максимально короткими. 
- 
Сжатие. Для семейств столбцов можно настроить различные алгоритмы сжатия. Выберите подходящий алгоритм сжатия в зависимости от типа данных и паттернов доступа в каждом семействе. 
- 
Хранение в памяти. Вы можете настроить хранение семейства столбцов в памяти для более быстрого доступа. Это полезно для часто используемых данных относительно небольшого объема. Однако следует учитывать использование памяти на серверах регионов. 
Пример
Рассмотрим таблицу, хранящую информацию о профиле пользователя, со следующими столбцами: user_id, username, email, first_name, last_name, address, city, state, zip и profile_picture. Семейства столбцов можно распределить следующим образом:
- 
info:username,email,first_name,last_name
- 
address:address,city,state,zip
- 
media:profile_picture
Такое устройство позволяет группировать часто используемую информацию о пользователе в семейство столбцов info, выделяет адресную информацию в другое семейство и помещает большие фотографии профиля в третье семейство, чтобы не влиять на производительность других запросов.
Стратегии индексирования
Phoenix предоставляет мощные возможности индексирования для ускорения выполнения запросов к данным HBase. В отличие от традиционных реляционных баз данных, где индексы обычно создаются для небольшого количества столбцов, Phoenix позволяет создавать индексы для любой комбинации столбцов, включая выражения и функции. Выбор правильной стратегии индексирования критически важен для оптимизации производительности запросов и минимизации затрат на обслуживание индексов.
В Phoenix существует два основных типа индексов: глобальные и локальные.
Глобальные индексы
Глобальные индексы хранятся в отдельной таблице HBase и охватывают все строки исходной таблицы. Когда запрос использует глобальный индекс, Phoenix извлекает данные из таблицы индекса, а не из исходной таблицы.
Глобальные индексы лучше всего подходят для рабочих нагрузок с высокой интенсивностью чтения, когда запросы часто фильтруют данные по индексированным столбцам. Они обновляются синхронно во время записи данных. Это может повлиять на производительность записи, особенно для больших наборов данных.
Глобальные индексы непригодны для использования, если базовая таблица недоступна.
Локальные индексы
Локальные индексы хранятся на тех же серверах регионов, что и исходные данные таблиц. Когда запрос использует локальный индекс, Phoenix извлекает данные из таблицы индексов и исходной таблицы на одном сервере регионов.
Локальные индексы идеально подходят для рабочих нагрузок с высокой интенсивностью записи, когда запросам требуется фильтрация по неведущим столбцам ключа строки или столбцам, не входящим в глобальный индекс. Они обновляются асинхронно после записи данных. Это минимизирует влияние на производительность записи.
Локальные индексы доступны, даже если базовая таблица недоступна.
Примеры синтаксиса для создания глобального и локального индексов:
CREATE INDEX my_index ON my_table (column1, column2);
CREATE LOCAL INDEX my_index ON my_table (column1, column2);Сжатие данных
Сжатие данных — важнейший метод экономии дискового пространства и повышения производительности ввода-вывода в HBase и Phoenix. Сжатие данных перед сохранением позволяет значительно сократить объем занимаемого дискового пространства и время чтения и записи данных. Однако сжатие также приводит к дополнительным затратам ресурсов процессора, связанным со сжатием и распаковкой данных. Выбор правильного алгоритма сжатия — это компромисс между экономией дискового пространства, производительностью ввода-вывода и загрузкой процессора.
HBase поддерживает несколько алгоритмов сжатия, перечисленных ниже, каждый из которых имеет свои особенности:
- 
NONE. Сжатие не используется. Это алгоритм по умолчанию. Он обеспечивает максимальную скорость чтения и записи, но требует больше всего дискового пространства. 
- 
LZO. Быстрый и широко используемый алгоритм сжатия, обеспечивающий хороший баланс между степенью сжатия и загрузкой процессора. Требует отдельной установки и настройки. 
- 
GZIP. Популярный алгоритм сжатия, обеспечивающий высокую степень сжатия, но потребляющий больше процессорных циклов, чем LZO. Подходит для данных, к которым редко обращаются. 
- 
Snappy. Быстрый алгоритм сжатия, ориентированный на скорость, а не на высокую степень сжатия. Идеально подходит для данных, к которым часто обращаются и которые требуют малой задержки. 
- 
LZ4. Чрезвычайно быстрый алгоритм сжатия, но обеспечивающий более низкую степень сжатия, чем другие алгоритмы. 
Оптимальный алгоритм сжатия для ваших данных зависит от нескольких факторов:
- 
Тип данных. Некоторые алгоритмы сжатия лучше подходят для определенных типов данных, чем другие. Например, GZIP часто подходит для текстовых данных, а Snappy — для двоичных. 
- 
Паттерны доступа. Если к данным обращаются часто, следует выбрать алгоритм сжатия с низкой задержкой, например, Snappy или LZ4. Если к данным обращаются редко, можно выбрать алгоритм сжатия с высокой степенью сжатия, например, GZIP. 
- 
Использование процессора. Учитывайте нагрузку на процессор при сжатии. Если ваша система уже ограничена ресурсами процессора, возможно, стоит выбрать менее ресурсоемкий алгоритм сжатия, например, LZO или Snappy. 
- 
Объем хранилища. Если объем хранилища ограничен, следует выбрать алгоритм сжатия с высокой степенью сжатия. 
Локальность данных
Локальность данных — ключевая концепция HBase и Phoenix, означающая близость данных к вычислительным ресурсам, которым требуется доступ к этим данным. Максимизация локальности данных критически важна для достижения высокой производительности, поскольку сокращает объем данных, передаваемых по сети, что может стать серьезным узким местом.
HBase хранит данные в регионах, распределенных по серверам регионов в кластере. Каждый сервер регионов отвечает за управление подмножеством данных. Когда клиентское приложение запрашивает данные, HBase пытается обработать запрос с сервера регионов, ближайшего к данным.
На локальность данных влияют следующие факторы:
- 
Конструкция ключа строки. Ключ строки — важнейший фактор, влияющий на локальность данных. Правильно спроектированный ключ строки группирует связанные данные на одном сервере регионов, что упрощает доступ к ним. 
- 
Разделение и объединение регионов. HBase автоматически разделяет и объединяет регионы в зависимости от размера данных и нагрузки. Если регионы разделяются и объединяются некорректно, локальность данных может пострадать. Важно отслеживать размеры регионов и соответствующим образом настраивать политики разделения и объединения регионов. 
- 
Размещение данных. HBase пытается разместить данные на серверах регионов, расположенных близко к потребителям данных. Однако такие факторы, как топология сети и rack awareness, могут влиять на размещение данных. 
- 
Сжатие. Сжатие — это процесс слияния и перезаписи файлов данных в HBase. Сжатие может улучшить локальность данных за счет реорганизации данных на диске. 
- 
Массовая загрузка. Использование массовой загрузки данных в HBase позволяет предварительно сортировать данные, что может улучшить локальность данных. 
Для улучшения локальности данных можно использовать следующие стратегии:
- 
Оптимальная конструкция ключа строки. Правильно спроектированный ключ строки крайне важен для локальности данных. Выберите ключ строки, который группирует связанные данные на одном сервере регионов. Рассмотрите возможность использования salting для предотвращения перегрузки, сохраняя при этом локальность связанных данных в пределах одного региона с salting. 
- 
Предварительное разделение. Предварительное разделение таблицы на несколько регионов может улучшить локальность данных за счет распределения данных по нескольким серверам регионов с самого начала. 
- 
Rack awareness. Настройте HBase с учетом топологии стоек физических серверов вашего кластера. Это позволит HBase размещать данные на серверах регионов, находящихся в той же стойке, где расположены потребители данных. 
- 
Конфигурация HDFS. Правильно настройте HDFS, чтобы обеспечить хранение данных в непосредственной близости от серверов регионов. 
Методы оптимизации запросов
План выполнения запроса
Понимание плана выполнения запроса имеет основополагающее значение для оптимизации SQL-запросов в Phoenix. План выполнения описывает шаги, которые Phoenix предпримет для извлечения и обработки данных. Анализируя этот план, вы можете выявить потенциальные узкие места и области для улучшения.
Вы можете получить план выполнения запроса с помощью оператора EXPLAIN PLAN в Phoenix.
Например:
EXPLAIN PLAN SELECT * FROM users WHERE age > 30 AND city = 'New York';Пример результата:
CLIENT 1-WAY PARALLEL 1/1 [SERVER FILTER]
    SERVER FILTER BY "AGE" > 30
        CLIENT 1-WAY FULL SCAN OVER USERS
План выполнения обычно представлен в виде древовидной структуры, где корневой узел представляет результат, а конечные узлы — источники данных. Каждый узел дерева описывает операцию, которую выполнит Phoenix. Ниже представлена таблица с описанием операций плана выполнения.
| Операция | Описание | 
|---|---|
| SERIAL | Указывает, что операция будет выполняться последовательно на одном сервере регионов. Это, как правило, менее эффективно, чем параллельное выполнение | 
| PARALLEL <n>-WAY | Указывает, что операция будет выполняться параллельно на нескольких серверах регионов, где  | 
| FULL SCAN OVER <table_name> | Обозначает полное сканирование таблицы, то есть Phoenix прочитает каждую строку в таблице, чтобы найти нужные. Полное сканирование таблицы чаще всего неэффективно, особенно для больших таблиц. Полное сканирование индексной таблицы бывает вполне эффективно | 
| RANGE SCAN OVER <table_name> <startRow, stopRow> | Обозначает сканирование диапазона, при котором Phoenix будет читать только подмножество строк таблицы на основе диапазона ключей строк. Это эффективнее, чем полное сканирование таблицы, но все еще может быть неэффективным, если диапазон слишком велик. Индексная таблица будет определять свои диапазоны иначе, чем исходная таблица | 
| POINT LOOKUP OVER <table_name> <rowKey> | Обозначает точечный поиск, при котором Phoenix напрямую извлекает одну строку по ее ключу. Это наиболее эффективный тип операции чтения | 
| CLIENT <op type> | Указывает, что выполнение запроса происходит на стороне клиента | 
| JOIN <join type> | Указывает тип выполненной операции  | 
| FILTER <predicate> | Указывает, что Phoenix фильтрует данные на основе предиката (предложения  | 
| AGGREGATE <aggregation function> | Указывает, что Phoenix выполняет функцию агрегации (например,  | 
| SORT | Указывает, что результаты сортируются. Сортировка может быть затратной, поэтому по возможности избегайте ее. Если вы можете использовать индекс для обеспечения требуемого порядка сортировки, сделайте это | 
На основе анализа плана выполнения вы можете предпринять шаги для повышения производительности запросов.
В приведенном выше примере вы можете создать индекс по столбцам age и city подобным образом:
CREATE INDEX idx_users_age_city ON users (age, city);После создания индекса план выполнения может выглядеть следующим образом:
CLIENT 1-WAY RANGE SCAN OVER IDX_USERS_AGE_CITY [30,]
    SERVER FILTER BY "CITY" = 'New York'
Эффективность SQL
Написание эффективных SQL-запросов имеет первостепенное значение для оптимальной производительности Phoenix. Хотя Phoenix использует HBase для хранения данных, неэффективное применение SQL может привести к медленному выполнению запросов даже при правильной индексации таблиц. В этом разделе рассматривается создание SQL-запросов, которые минимизируют нагрузку на Phoenix и максимально используют ресурсы.
Ключевые принципы написания эффективного SQL-запроса:
- 
Выбирайте только необходимые столбцы. Явно указывайте нужные столбцы в предложении SELECT. Использование предложенияSELECT *позволяет извлечь все столбцы из таблицы, даже если вам нужны лишь некоторые из них. Это увеличивает объем данных, которые необходимо прочитать, передать и обработать.
- 
Выполняйте фильтрацию эффективно и на ранней стадии. Применение фильтров на поздних этапах выполнения запроса (например, после полного сканирования таблицы) может быть крайне неэффективным. Используйте предложение WHEREдля фильтрации данных на максимально ранней стадии. Убедитесь, что предложениеWHEREиспользует доступные индексы. Наиболее строгие условия следует размещать в предложенииWHEREв первую очередь.
- 
Используйте правильные типы данных. Несоответствие типов данных в сравнениях и предикатах может помешать Phoenix эффективно использовать индексы и привести к дополнительным расходам ресурсов на преобразование типов. Убедитесь, что типы данных в ваших SQL-запросах соответствуют типам данных соответствующих столбцов в схеме таблицы. 
- 
Используйте встроенные функции эффективно. Некоторые встроенные функции могут быть эффективнее других. Изучите характеристики производительности различных встроенных функций. Используйте функции, оптимизированные для HBase/Phoenix. 
- 
Избегайте ненужных подзапросов. Подзапросы часто можно переписать как объединения, что может быть более эффективно в Phoenix. Коррелированные подзапросы (подзапросы, зависящие от внешнего запроса) могут быть особенно проблемными. Старайтесь переписывать подзапросы как объединения, когда это возможно. Рассмотрите денормализацию в качестве альтернативы, если подзапрос используется часто. 
- 
Ограничьте набор результатов. Получение больших наборов результатов может создать нагрузку на клиент и сеть. Используйте предложение LIMITдля ограничения количества возвращаемых строк. Если требуется разбиение на страницы, используйтеLIMITиOFFSETвместе.
- 
Используйте COUNT(*) с осторожностью. Функция COUNT(*)для большой таблицы без предложенияWHEREможет быть очень затратной, так как требует сканирования всей таблицы. Если нужно подсчитать все строки в таблице, рассмотрите возможность использования предварительного агрегированного подсчета или облегченного подхода, если таблица не слишком большая. По возможности добавьте предложениеWHERE, чтобы ограничить подсчет меньшим подмножеством данных.
- 
Используйте UPSERT SELECT для эффективного обновления и вставки данных. Вставка данных построчно может быть очень неэффективной. Используйте UPSERT SELECTдля пакетной вставки или обновления данных. Это особенно полезно при загрузке данных из других таблиц или внешних источников.
Оптимизация JOIN
Объединения в Phoenix могут быть относительно затратными операциями по сравнению с точечным поиском или сканированием диапазонов. Поэтому оптимизация объединений критически важна для достижения высокой производительности при работе со связанными данными в нескольких таблицах. Распределенная природа HBase делает производительность объединений более важной, чем в традиционных реляционных базах данных. В этом разделе представлены стратегии оптимизации объединений в Phoenix, включая выбор правильного типа объединения, использование локальности данных и, при необходимости, полный отказ от объединений посредством денормализации.
Phoenix поддерживает несколько типов объединений и связанных с ними стратегий, каждая из которых обладает своими характеристиками производительности:
- 
Star join. Оптимизированы для сценариев, когда одна большая таблица (таблица фактов) объединяется с несколькими меньшими таблицами измерений. Phoenix пытается транслировать только те части таблиц измерений, которые требуются запросу, на все соответствующие серверы регионов (содержащие данные из таблицы фактов в объединении), что обеспечивает эффективные локальные объединения. Это часто предпочтительная стратегия объединения в Phoenix, если модель данных и паттерны запросов ее поддерживают. Phoenix обычно может определить целесообразность выполнения star join на основе доступной ему статистики данных. 
- 
Broadcast join. Оптимизированы для сценариев, когда одна таблица действительно небольшая (с запасом помещается в памяти на каждом сервере регионов) и объединяется с одной или несколькими более крупными таблицами. Phoenix передает всю небольшую таблицу на все серверы регионов. Это отличается от star join, при котором отправляются только необходимые части таблиц измерений. Такой подход может обеспечить отличную производительность, поскольку операции объединения выполняются локально на каждом сервере регионов, что минимизирует передачу данных. Phoenix автоматически использует эту оптимизацию, когда это применимо. 
- 
Sort-merge join. Хотя Phoenix поддерживает объединения типа sort-merge, они, как правило, менее эффективны, чем объединения типа star или broadcast, особенно в распределенных средах, таких как HBase. Они предполагают сортировку входных таблиц по ключам объединения с последующим слиянием отсортированных результатов. Узкое место производительности возникает из-за дополнительных расходов ресурсов на сортировку и потенциального перемешивания данных по сети. Phoenix обычно прибегает к объединениям типа sort-merge только в тех случаях, когда невозможно применить другие, более эффективные стратегии объединения. Это может произойти, если таблицы очень большие и не могут быть эффективно переданы, или если ключи объединения не подходят для объединения на основе хеша. 
Возможные стратегии оптимизации объединений:
- 
Денормализация. Часто наилучшей оптимизацией для объединений является их полное исключение. Рассмотрите возможность денормализации данных путем встраивания связанной информации непосредственно в таблицу фактов или создания предобъединенных представлений. Например, вместо объединения таблиц ordersиcustomersдля получения информации о клиенте по каждому заказу, можно включить соответствующие данные о клиенте (например, имя клиента, город) непосредственно в таблицуorders. Однако денормализация может привести к избыточности данных и потенциальным проблемам с согласованностью, поэтому тщательно взвесьте все за и против, исходя из вашего конкретного варианта использования.
- 
Локальность данных. Размещайте связанные таблицы на одних серверах регионов, чтобы минимизировать сетевой трафик во время объединений. Этого можно добиться с помощью стратегий совместного размещения в HBase. 
- 
Выбор правильного порядка объединений. Порядок объединения таблиц может существенно влиять на производительность. Как правило, лучше всего начинать с таблицы с наиболее строгим фильтром и объединять ее с другими таблицами по возрастанию их размера. Ранняя фильтрация сокращает объем данных, необходимых для обработки в последующих операциях объединения. 
- 
Фильтрация перед объединением. Применяйте предложения WHEREдля фильтрации данных из каждой таблицы перед операциейJOIN. Уменьшение размера объединяемых таблиц повышает производительность объединения.
- 
Объединения типа broadcast для небольших таблиц. Для объединений, включающих небольшую таблицу измерений и большую таблицу фактов, используйте объединение типа broadcast. Такие объединения копируют меньшую таблицу на все серверы регионов, что позволяет выполнять локальные объединения с большей таблицей. Phoenix может автоматически выбирать объединение типа broadcast при обнаружении небольшой таблицы. Вы часто можете повлиять на это решение с помощью подсказок. 
- 
Используйте оптимизацию объединения типа star. Если ваша модель данных соответствует схеме star (одна большая таблица фактов, объединенная с несколькими меньшими таблицами измерений), воспользуйтесь оптимизацией объединения типа star в Phoenix. 
Подсказки
Подсказки — это директивы, которые можно добавлять в SQL-запросы для управления планом выполнения запросов в Phoenix. Они позволяют направлять работу оптимизатора и потенциально повышать производительность, когда план выполнения по умолчанию неоптимален. Хотя Phoenix автоматически оптимизирует запросы, подсказки позволяют переопределять его решения в определенных ситуациях. Используйте подсказки с осторожностью, так как они могут сделать ваши запросы менее приспособленными к портированию и более сложными в дальнейшей поддержке.
Подсказки размещаются после ключевых слов SELECT, INSERT, UPDATE или DELETE и имеют следующий синтаксис:
SELECT /*+ hint1, hint2, ... */ column1, column2 FROM table_name WHERE condition;При использовании подсказок учитывайте следующее:
- 
Используйте с осторожностью. Подсказки переопределяют оптимизатор запросов по умолчанию, что может скрывать изначально существующие проблемы с производительностью или приводить к неоптимальным планам при неправильном использовании. 
- 
Тщательно тестируйте. Всегда проверяйте производительность запросов с подсказками и без них, чтобы убедиться, что использование подсказки действительно улучшает производительность. 
- 
Обеспечивайте удобство поддержки. Подсказки могут сделать ваши запросы менее портативными и более сложными в обслуживании. Задокументируйте причины использования подсказки и отслеживайте ее эффективность с течением времени. 
- 
Помните об изменениях в оптимизаторе. Оптимизатор запросов Phoenix может измениться в будущих версиях, сделав ваши подсказки неэффективными или даже вредными. Регулярно проверяйте и обновляйте подсказки по мере необходимости. 
- 
Понимайте план выполнения. Используйте функцию EXPLAIN PLAN, чтобы понять, как ваши подсказки влияют на план выполнения запроса.
Сервер запросов
Сервер запросов Phoenix (Phoenix Query Server, PQS) предоставляет доступ к Phoenix клиентам, не имеющим прямого доступа к кластеру HBase. Он действует как прокси-сервер, позволяя клиентам отправлять SQL-запросы через тонкий драйвер JDBC, абстрагируясь от сложностей прямого взаимодействия с HBase. Такой подход полезен в ситуациях, когда ограничения безопасности, сетевые конфигурации или зависимости на стороне клиента препятствуют прямому подключению к кластеру HBase.
Phoenix Query Server имеет клиент-серверную архитектуру:
- 
Клиент. Клиентское приложение использует тонкий драйвер JDBC для подключения к PQS. Этот драйвер часто менее ресурсоемкий, чем стандартный драйвер Phoenix JDBC, поскольку ему не нужно обрабатывать прямые соединения с HBase. 
- 
Сервер запросов Phoenix. PQS — это автономный процесс, работающий вне кластера HBase (хотя часто размещается на узлах HBase). Он получает SQL-запросы от клиентов, преобразует их в запросы Phoenix, выполняет их в кластере HBase и возвращает результаты клиенту. PQS выполняет такие задачи, как: - 
Аутентификация и авторизация. 
- 
Анализ и оптимизация запросов (с помощью внутреннего оптимизатора Phoenix). 
- 
Организация пула подключений к HBase. 
- 
Управление наборами результатов. 
 
- 
- 
Кластер HBase. Кластер HBase хранит данные и выполняет операции доступа к ним. PQS подключается к кластеру HBase с помощью стандартного драйвера Phoenix JDBC. 
Преимущества использования Phoenix Query Server:
- 
Упрощенный клиентский доступ. Клиенты могут получать доступ к данным Phoenix через стандартный интерфейс JDBC, без необходимости установки полных клиентских библиотек Phoenix или прямого доступа к кластеру HBase. 
- 
Безопасность. PQS предоставляет центральную точку аутентификации и авторизации, позволяя контролировать доступ к данным Phoenix. Вы можете ограничить прямой доступ к кластеру HBase, повышая таким образом уровень безопасности. 
- 
Сетевая изоляция. PQS может быть развернут в DMZ или другой защищенной сетевой зоне, изолируя кластер HBase от прямого доступа клиентов. Это критически важно для безопасности во многих организациях. 
- 
Управление ресурсами. PQS может управлять подключениями к кластеру HBase, предотвращая перегрузку кластера клиентами со слишком большим количеством подключений. Это обеспечивает множественность подключений и управление ресурсами. 
- 
Независимость от языка. Клиенты могут быть написаны на любом языке, поддерживающем JDBC, что обеспечивает гибкость в разработке приложений. 
- 
Тонкий драйвер JDBC. Клиент JDBC имеет небольшой размер, что упрощает его развертывание на различных платформах.