Рекомендации по масштабированию и улучшению времени выполнения «сводного запроса» к таблице с миллиардом строк, увеличивая один миллион в день - PullRequest
2 голосов
/ 16 июня 2009

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

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

<b>Items</b>

| Id | Name   |
|----|--------|
| 1  | Sample |
<b>Items_Attributes</b>

| ItemId | AttributeId |
|--------|-------------|
| 1      | 1           |
| 1      | 2           |
<b>Attributes</b>

| Id | AttributeTypeId | Value |
|----|-----------------|-------|
| 1  | 1               | 500mB |
| 2  | 2               | 1.0.0 |
<b>AttributeTypes</b>

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

Существует много различных типов текстовых файлов с различными метаданными внутри. Для каждого текстового файла у нас есть Item, а для каждого извлеченного значения метаданных у нас есть Attribute<code>.</p> <p><code>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
</code>

вернет поворотную таблицу, как это

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

Приложение работало в течение нескольких месяцев, и его производительность ужасно снизилась в тот момент, когда он больше не используется. Отчеты должны занимать не более 2 секунд, а таблица Items_Attributes увеличивается в среднем на 10 000 000 строк в неделю. Все правильно проиндексировано, и мы потратили много времени на анализ и оптимизацию планов выполнения запросов.

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

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

  • Купите больше оборудования и настройте кластер SQL Server. (нам нужен совет по правильной стратегии «кластеризации»)
  • Использовать базу данных ключ / значение, такую ​​как HBase (мы не знаем, решит ли она нашу проблему)
  • Используйте СУБД, а не СУБД (мы рассматривали db4o)
  • Переместите наше программное обеспечение в облако (у нас нет опыта)
  • Статически генерировать отчеты во время выполнения. (мы не очень хотим)
  • Статические индексированные представления для общих отчетов (производительность практически одинакова)
  • Денормализация схемы (в некоторых наших отчетах используется до 50 таблиц в одном запросе)

Ответы [ 7 ]

2 голосов
/ 16 июня 2009

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

| ItemName | Размер | Версия | | ---------- | ------- | --------- | | Образец | 500 мб | 1.0.0 |

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

2 голосов
/ 16 июня 2009

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

2 голосов
/ 16 июня 2009

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

С вашей текущей таблицей, запрос похож на этот:

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

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

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

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

id  name  size  version

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

1 голос
/ 16 июня 2009

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

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

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

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

SELECT FROM Items WHERE ID = 1

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

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

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

1 голос
/ 16 июня 2009

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

0 голосов
/ 17 июня 2009

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

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

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

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

0 голосов
/ 16 июня 2009

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

Предполагается, что вы не пытаетесь сообщить обо всех ItemId с.

...