Настройка производительности запросов в Azure Cosmos DB

ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL

Azure Cosmos DB предоставляет API для NoSQL для запроса данных без необходимости использовать схему или вторичные индексы. В этой статье содержатся следующие сведения для разработчиков:

  • общие сведения о выполнении SQL-запросов в Azure Cosmos DB;
  • советы и рекомендации по повышению производительности запросов.
  • Примеры использования метрик выполнения SQL-запросов для отладки производительности запросов

Сведения о выполнении SQL-запросов

Данные Azure Cosmos DB хранятся в контейнерах, которые могут увеличиваться до любого размера хранилища или пропускной способности запроса. Azure Cosmos DB легко масштабирует данные между физическими секциями под обложками для обработки роста или увеличения подготовленной пропускной способности. Вы можете выполнять SQL-запросы к любому контейнеру с помощью REST API или одного из поддерживаемых пакетов SDK для SQL.

Рассмотрим пример секционирования. Вы определяете ключ секции, например city, который определяет, каким образом данные разделяются на физические секции. Данные, принадлежащие одному ключу секции (например, "city" == "Сиэтл") хранятся в физической секции, а одна физическая секция может хранить данные из нескольких ключей секций. Когда секция достигает предела хранилища, служба легко разбивает секцию на две новые секции. Данные распределяются равномерно по новым секциям, сохраняя все данные для одного ключа секции вместе. Так как секции являются временными, API используют абстракцию диапазона ключей секции, который обозначает диапазоны хэшей ключей секций.

При выполнении запроса к базе данных Azure Cosmos DB пакет SDK выполняет следующие логические действия.

  • Анализ SQL-запроса для определения плана выполнения запроса.
  • Если запрос включает фильтр по ключу секции, например SELECT * FROM c WHERE c.city = "Seattle", он направляется в одну секцию. Если запрос не содержит фильтр ключа секции, он выполняется во всех секциях и результатах каждой секции объединяются на стороне клиента.
  • Запрос выполняется в каждой секции последовательно или параллельно в зависимости от конфигурации клиента. В каждой секции запрос может совершить один или несколько циклов приема-передачи в зависимости от сложности запроса, выбранного размера страницы и подготовленной пропускной способности коллекции. Каждое выполнение возвращает количество единиц запросов, потребляемых статистикой выполнения запросов и выполнения запросов.
  • Пакет SDK выполняет суммирование результатов запросов в секциях. Например, если запрос включает предложение ORDER BY в секциях, тогда результаты из отдельных секций сортируются слиянием для возвращения результатов в глобально отсортированном виде. Если запрос является агрегированием, например COUNT, счетчики отдельных секций суммируются в общий счетчик.

Пакеты SDK предоставляют различные параметры выполнения запросов. Например, в .NET эти параметры доступны в классе QueryRequestOptions. В следующей таблице описаны эти параметры и как они влияют на время выполнения запроса.

Параметр Описание
EnableScanInQuery Применяется, только если индексирование для запрашиваемого пути фильтра отключено. Необходимо задать значение true, если вы отказались от индексирования и хотите выполнить запросы с помощью полной проверки.
MaxItemCount Максимальное количество элементов, возвращаемых на сервер за круговой путь. Вы можете задать для него значение -1, чтобы сервер управлял количеством возвращаемых элементов.
MaxBufferedItemCount Максимальное количество элементов, которые могут быть буферированы на стороне клиента во время параллельного выполнения запроса. Положительное значение свойства ограничивает количество буферированных элементов заданным значением. Вы можете задать значение меньше 0, чтобы система автоматически решила количество элементов для буфера.
MaxConcurrency Возвращает или задает количество параллельных операций, выполняемых на стороне клиента во время параллельного выполнения запроса. Положительное значение свойства ограничивает число параллельных операций до заданного значения. Вы можете задать значение меньше 0, чтобы система автоматически решила количество параллельных операций для выполнения.
PopulateIndexMetrics Позволяет собирать метрики индекса, чтобы понять, как обработчик запросов использовал существующие индексы и как он может использовать потенциальные новые индексы. Этот параметр вызывает издержки, поэтому его следует включить только при отладке медленных запросов.
ResponseContinuationTokenLimitInKb Можно ограничить максимальный размер маркеров продолжения, возвращаемых сервером. Это может потребоваться задать, если узел приложения имеет ограничения на размер заголовка ответа, но он может увеличить общую длительность и ЕЗ, использованные для запроса.

Например, ниже приведен запрос к контейнеру, секционированного /city с помощью пакета SDK для .NET:

QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.city = 'Seattle'");
QueryRequestOptions options = new QueryRequestOptions()
{
    MaxItemCount = -1,
    MaxBufferedItemCount = -1,
    MaxConcurrency = -1,
    PopulateIndexMetrics = true
};
FeedIterator<dynamic> feedIterator = container.GetItemQueryIterator<dynamic>(query);

FeedResponse<dynamic> feedResponse = await feedIterator.ReadNextAsync();

Каждое выполнение запроса соответствует REST API POST с заголовками, заданными для параметров запроса и SQL-запроса в тексте. Сведения о заголовках запросов и параметрах интерфейса REST API см. в статье Querying Azure Cosmos DB resources using the REST API (Запрос ресурсов Azure Cosmos DB с помощью REST API).

Рекомендации по повышению производительности запросов

Следующие факторы обычно влияют на производительность запросов Azure Cosmos DB. Мы глубже рассмотрим каждый из этих факторов в этой статье.

Множитель Совет
Подготовленная пропускная способность Измерьте единицы запроса на запрос и убедитесь в наличии необходимой подготовленной пропускной способности для запросов.
Секционирование и ключи секций Отдайте предпочтение запросам со значением ключа секции в предложении фильтра, чтобы обеспечить низкую задержку.
Параметры пакета SDK и запроса Следуйте рекомендациям по работе с пакетами SDK, таким как прямое подключение, а также настройте параметры выполнения запросов на стороне клиента.
Задержка в сети Запустите приложение в том же регионе, что и учетная запись Azure Cosmos DB, где это возможно, чтобы уменьшить задержку.
Политика индексирования Проверьте наличие необходимых путей и политик индексирования запросов.
Метрики выполнения запросов Проанализируйте метрики выполнения запросов, чтобы определить потенциальные перезаписи запросов и форм данных.

Подготовленная пропускная способность

В Azure Cosmos DB создаются контейнеры данных с зарезервированной пропускной способностью, выраженной в единицах запросов (ЕЗ) в секунду. Чтение 1-КБ документа составляет один ЕЗ, и каждая операция (включая запросы) нормализуется до фиксированного количества единиц запросов на основе его сложности. Например, если для контейнера подготовлено 1000 ЕЗ/с, и у вас есть запрос, который SELECT * FROM c WHERE c.city = 'Seattle' потребляет 5 единиц запросов, можно выполнить (1000 ЕЗ/с) / (5 ЕЗ/запрос) = 200 из этих запросов в секунду.

Если вы отправляете более 200 запросов в секунду (или некоторые другие операции, которые насыщают все подготовленные ЕЗ), служба запускает ограничение скорости входящих запросов. Пакеты SDK автоматически обрабатывают ограничение скорости, выполняя обратный выход или повтор, поэтому вы можете заметить более высокую задержку для этих запросов. Увеличение подготовленной пропускной способности до требуемого значения улучшит задержку при обработке запросов и пропускную способность.

Дополнительные сведения о единицах запроса см. в статье Единицы запросов в базе данных Azure Cosmos DB.

Секционирование и ключи секций

При использовании Azure Cosmos DB следующие сценарии чтения данных упорядочены от того, что обычно является самым быстрым и наиболее эффективным до самого медленного или наименее эффективного.

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

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

Если вы хотите узнать больше о секционировании и ключах секций, ознакомьтесь со статьей Секционирование и масштабирование в базе данных Azure Cosmos DB.

Параметры пакета SDK и запроса

Ознакомьтесь с советами по производительности запросов и тестированием производительности, чтобы получить лучшую производительность на стороне клиента из Azure Cosmos DB с помощью наших пакетов SDK.

Задержка в сети

Сведения о настройке глобального распространения и подключении к ближайшему региону см. в статье о глобальном распределении Azure Cosmos DB. Задержка в сети оказывает значительное влияние на производительность запросов, если необходимо выполнить несколько цикловых поездок или получить большой результирующий набор из запроса.

Вы можете использовать метрики выполнения запросов для получения времени выполнения сервера запросов, что позволяет различать время выполнения запроса из времени, затраченного на передачу сети.

Политика индексирования

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

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

Метрики выполнения запросов

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

Дополнительные сведения о получении метрик запроса.

Metric Единица измерения Description
TotalTime мс Общее время выполнения запроса
DocumentLoadTime мс Время загрузки документов
DocumentWriteTime мс Время, затраченное на запись и сериализацию выходных документов
IndexLookupTime мс Время, затраченное на физическом уровне индекса
QueryPreparationTime мс Время, затраченное на подготовку запроса
RuntimeExecutionTime мс Общее время выполнения запроса
VMExecutionTime мс Время, затраченное на выполнение запроса во время выполнения запроса
OutputDocumentCount count Количество выходных документов в результирующем наборе
OutputDocumentSize count Общий размер выходных документов в байтах
RetrievedDocumentCount count Общее число полученных документов
RetrievedDocumentSize байт Общий размер полученных документов в байтах
IndexHitRatio отношение [0,1] Отношение числа документов, соответствующих фильтру, к количеству загруженных документов

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

Ниже приведены некоторые примеры запросов и интерпретации некоторых метрик, возвращаемые из выполнения запроса.

Query Образец метрики Description
SELECT TOP 100 * FROM c "RetrievedDocumentCount": 101 Количество полученных документов составляет 100+1 для соответствия предложению TOP. Время запроса в основном тратится WriteOutputTime и DocumentLoadTime так как это сканирование.
SELECT TOP 500 * FROM c "RetrievedDocumentCount": 501 RetrievedDocumentCount теперь выше (500+1 для соответствия предложению TOP).
SELECT * FROM c WHERE c.N = 55 "IndexLookupTime": "00:00:00.0009500" Около 0,9 мс затрачивается IndexLookupTime на поиск ключа, так как это поиск по индексу /N/?.
SELECT * FROM c WHERE c.N > 55 "IndexLookupTime": "00:00:00.0017700" Немного больше времени (1,7 мс) затрачивается IndexLookupTime на сканирование диапазона, так как это поиск по индексу /N/?.
SELECT TOP 500 c.N FROM c "IndexLookupTime": "00:00:00.0017700" На DocumentLoadTime затрачивается то же время, что и в предыдущих запросах, но с меньшим DocumentWriteTime, так как мы отображаем только одно свойство.
SELECT TOP 500 udf.toPercent(c.N) FROM c "RuntimeExecutionTime": "00:00:00.2136500" Около 213 мс затрачивается RuntimeExecutionTime на выполнение определяемой пользователем функции для каждого значения c.N.
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(c.Name, 'Den') "IndexLookupTime": "00:00:00.0006400", "RuntimeExecutionTime": "00:00:00.0074100" Около 0,6 мс затрачивается IndexLookupTime на /Name/?. Большая часть времени выполнения запроса (~7 мс) затрачивается на RuntimeExecutionTime.
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(LOWER(c.Name), 'den') "IndexLookupTime": "00:00:00", "RetrievedDocumentCount": 2491, "OutputDocumentCount": 500 Запрос выполняется как операция сканирования, так как он использует LOWER, и 500 из 2491 полученных документов возвращаются.

Следующие шаги