Рекомендации о том, как масштабировать и улучшать время выполнения “сводного запроса” в таблице с миллиардом строк, увеличивая его на миллион в день

StackOverflow https://stackoverflow.com/questions/1002086

Вопрос

Наша компания разрабатывает внутренний проект по разбору текстовых файлов.Эти текстовые файлы состоят из метаданных, которые извлекаются с помощью обычных выражений.Десять компьютеров круглосуточно анализируют текстовые файлы и загружают извлеченные метаданные в базу данных Intel Xeon SQL Server 2005 высокого класса.

Упрощенная схема базы данных выглядит следующим образом:

Товары

| Id | Name   |
|----|--------|
| 1  | Sample |
Items_атрибуты

| ItemId | AttributeId |
|--------|-------------|
| 1      | 1           |
| 1      | 2           |
Атрибуты

| Id | AttributeTypeId | Value |
|----|-----------------|-------|
| 1  | 1               | 500mB |
| 2  | 2               | 1.0.0 |
Типы атрибутов

| Id | Name    |
|----|---------|
| 1  | Size    |
| 2  | Version |

Существует множество различных типов текстовых файлов с различными метаданными внутри.Для каждого текстового файла у нас есть Item и для каждого извлеченного значения метаданных у нас есть Attribute.

Items_Attributes позвольте нам избежать дублирования Attribute значения, которые позволяют избежать увеличения размера базы данных на x ^ 10.

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

Кроме того, это позволяет нам фильтровать данные и получать динамические отчеты на основе пользовательских критериев.Мы фильтруем по Attribute а затем поворачиваем результирующий набор (http://msdn.microsoft.com/en-us/library/ms177410.aspx).Итак, этот пример псевдо-sql-запроса

SELECT FROM Items WHERE Size = @A AND Version = @B

вернул бы сводную таблицу, подобную этой

| ItemName | Size  | Version |
|----------|-------|---------|
| Sample   | 500mB | 1.0.0   |

The application has been running for months and performance decreased terribly at the point is no longer usable. Reports should take no more than 2 seconds and Items_Attributes таблица увеличивается в среднем на 10 000 000 строк в неделю.Все правильно проиндексировано, и мы потратили немало времени на анализ и оптимизацию планов выполнения запросов.

Итак, мой вопрос в том, как бы вы масштабировали это, чтобы сократить время выполнения отчета?

Мы пришли с этими возможными решениями:

  • Купите больше оборудования и настройте кластер SQL Server.(нам нужен совет по правильной стратегии "кластеризации")
  • Используйте базу данных ключей / значений, такую как HBase (мы действительно не знаем, решит ли это нашу проблему)
  • Используйте ODBMS, а не RDBMS (мы рассматривали db4o)
  • Перенести наше программное обеспечение в облако (у нас нет никакого опыта)
  • Статически генерируйте отчеты во время выполнения.(на самом деле мы этого не хотим)
  • Статические индексированные представления для обычных отчетов (производительность почти такая же)
  • Отмена нормализации схемы (некоторые из наших отчетов содержат до 50 таблиц в одном запросе)
Это было полезно?

Решение

Возможно, этот технический документ команды SQL Server CAT о подводных камнях модели базы данных Entity-Attribute-Value может помочь: http://sqlcat.com/whitepapers/archive/2008/09/03/best-practices-for-semantic-data-modeling-for-performance-and-scalability.aspx

Другие советы

Я бы начал с публикации точных метаданных таблиц (вместе с деталями индексации), точного текста запроса и плана выполнения.

При вашем текущем макете таблицы запрос, подобный этому:

SELECT FROM Items WHERE Size = @A AND Version = @B

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

Вы даже не можете создать индексированное представление, так как оно содержало бы самосоединение на attributes.

Вероятно, лучшим решением было бы денормализовать таблицу следующим образом:

id  name  size  version

и создайте индекс на (size, version)

Работал с такими схемами много времени.Они никогда не работают хорошо.Лучше всего просто хранить данные так, как вам это нужно, в форме:

| Имя элемента | Размер | Версия | |----------|-------|---------| | Образец | 500 МБ | 1.0.0 |

Тогда вам не нужно поворачиваться.И кстати, пожалуйста, не называйте вашу исходную схему EAV "нормализованной" - она не нормализована.

На мой взгляд, это похоже на выдачу нескольких OLAP-запросов к базе данных, оптимизированной для OLTP-транзакций.Не зная подробностей, я бы рекомендовал создать отдельное "хранилище данных", оптимизированное для того типа запросов, которые вы выполняете.Это включало бы агрегирование данных (если возможно), денормализацию, а также наличие базы данных, которой исполнился 1 день или около того.Вы бы постепенно обновляли данные каждый день или с любым интервалом по вашему желанию.

Пожалуйста, опубликуйте точный DDL и индексы, если у вас есть индексы в столбцах идентификаторов, то ваш запрос приведет к сканированию

вместо чего-то подобного этому

SELECT FROM Items WHERE Size = @A AND Version = @B

тебе нужно это сделать

SELECT FROM Items WHERE ID = 1

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

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

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

Краткосрочным решением может быть использование горизонтальное разделение.Я предполагаю, что ваш самый большой стол - это Items_Attributes.Вы могли бы разделить эту таблицу по горизонтали, поместив каждый раздел в отдельную файловую группу на отдельном контроллере диска.

Это при условии, что вы не пытаетесь сообщать обо всех ItemIds сразу.

Вы упоминаете 50 таблиц в одном запросе.Хотя SQL server поддерживает до 256 таблиц в одном монолитном запросе, использование такого подхода снижает шансы оптимизатора на создание эффективного плана.

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

Кроме того (это немного рискованно), вы не говорите, на какой версии SQL server вы работаете;но если вы используете SQL 2005, учитывая количество таблиц, задействованных в ваших отчетах, и объем данных, стоит проверить, что ваш SQL server исправлен по крайней мере до SP2.

Я работал над проектом ETL с использованием таблиц с числом строк в сотни миллионов, где мы обнаружили, что оптимизатор запросов в SQL 2005 RTM / SP1 не может последовательно создавать эффективные планы для запросов, объединяющих более 5 таблиц, где одна или несколько таблиц имеют такой масштаб.Эта проблема была решена в SP2.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top