Как вы подходите для оптимизации больших таблиц (+ 1M строк) на SQL Server? - PullRequest
13 голосов
/ 03 декабря 2008

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

Теперь мой первый подход к оптимизации состоял в том, чтобы сохранить данные до минимального размера, поэтому я уменьшил размер строки в среднем до 60 байт со следующими столбцами:

[Stock] [int] NOT NULL
[Date] [smalldatetime] NOT NULL
[Open] [smallmoney] NOT NULL
[High] [smallmoney] NOT NULL
[Low] [smallmoney] NOT NULL
[Close] [smallmoney] NOT NULL
[Trades] [int] NOT NULL
[Quantity] [bigint] NOT NULL
[Volume] [money] NOT NULL

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

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

Сейчас, имея полмиллиона записей, требуется 200 мс , чтобы выбрать 700 кавычек из определенного актива. Я считаю, что это число будет расти с ростом таблицы.

Теперь о третьем подходе, который я подумываю разделить на три таблицы, каждая для определенного рынка (акции, опционы и форварды). Это, вероятно, сократит размер стола на 1/3. Теперь этот подход поможет или он не имеет большого значения? На данный момент размер таблицы составляет 50 МБ, поэтому он может без проблем помещаться в оперативной памяти.

Другим подходом было бы использование функции секционирования SQL Server. Я не знаю много об этом, но я думаю, что он обычно используется, когда таблицы большие, и вы можете распределить по нескольким дискам, чтобы уменьшить задержку ввода-вывода, я прав? Будет ли полезным в этом случае разделение? Я полагаю, что могу разделить самые новые значения (последние годы) и самые старые значения в разных таблицах. Вероятность поиска самых новых данных выше, и с небольшим разделом это, вероятно, будет быстрее, верно?

Какие были бы другие хорошие подходы, чтобы сделать это максимально быстрым? Основное использование таблицы выбирается для поиска определенного диапазона записей по конкретному активу, например за последние 3 месяца актива X. Будут другие варианты использования, но это будет наиболее распространенным способом, который может быть выполнен более чем на 3 тыс. пользователи одновременно.

Ответы [ 9 ]

11 голосов
/ 14 декабря 2008
  1. При 1 миллионе записей я не считаю эту таблицу особенно большой, требующей необычных методов оптимизации, таких как разбиение таблицы, денормализация и т. Д. Но эти решения будут приняты, когда вы попробуете все обычные средства, которые не не влияет на вашу способность использовать стандартные методы запросов.

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

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

Это логически верно - кластеризованный индекс определяет логический порядок записей на диске, и это все, что вас должно беспокоить. SQL Server может отказаться от накладных расходов на сортировку в физическом блоке, но он все равно будет вести себя так, как если бы он был, поэтому это не имеет значения. В любом случае запрос на одну акцию, вероятно, будет считан на 1 или 2 страницы; и оптимизатор не получает много пользы от неупорядоченных данных на странице, прочитанной.

В настоящее время с полмиллиона записей требуется около 200 мс, чтобы выбрать 700 цитат из определенного актива. Я считаю, что это число будет расти с ростом таблицы.

Не обязательно значительно. Не существует линейной зависимости между размером таблицы и скоростью запроса. Обычно есть намного больше соображений, которые более важны. Я не буду беспокоиться об этом в диапазоне, который вы описываете. Это причина, по которой вы обеспокоены? Мне кажется, что 200 мс - это здорово, этого достаточно для того, чтобы вы достигли момента, когда ваши таблицы будут загружены, и вы сможете приступить к реалистичному тестированию и получить гораздо лучшее представление о реальной производительности.

Теперь о третьем подходе, который я подумываю разделить на три таблицы, каждая для определенного рынка (акции, опционы и форварды). Это, вероятно, сократит размер стола на 1/3. Теперь этот подход поможет или он не имеет большого значения? На данный момент размер таблицы составляет 50 МБ, поэтому он может без проблем помещаться в оперативной памяти.

Нет! Такая оптимизация настолько преждевременна, что, вероятно, мертворождена.

Другим подходом было бы использование функции разделения SQL Server.

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

Какие были бы другие хорошие подходы, чтобы сделать это максимально быстрым?

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

10 голосов
/ 03 декабря 2008

Миллион записей на самом деле не такой большой. Похоже, поиск занимает слишком много времени - индексируется ли столбец, по которому вы ведете поиск?

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

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

3 голосов
/ 03 декабря 2008

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

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

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

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

Но, опять же, ключом к этому являются индексы, пока не связывайтесь с разбиением и прочим ... особенно с миллионными записями, вот и все, у меня есть таблицы с 150-миллионными записями, а возвращение 40-тысячных записей приводит двигатель 1500 мс ...

3 голосов
/ 03 декабря 2008

Сначала проверьте свой план выполнения по этому запросу. Убедитесь, что ваши индексы используются. Я нашел это. Миллион записей не много. Чтобы дать некоторую перспективу, у нас была таблица инвентаризации с 30 миллионами строк и весь наш запрос, который объединял тонны таблиц и выполнял много вычислений, мог выполняться менее чем за 200 мс. Мы обнаружили, что на 64-битном сервере quad proc у нас может быть значительно больше записей, поэтому мы никогда не беспокоимся о разбиении.

Вы можете использовать SQL Profier для просмотра плана выполнения или просто запустить запрос из SQL Management Studio или Query Analyzer.

1 голос
/ 04 декабря 2008

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

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

1 голос
/ 03 декабря 2008

Я работаю в школьном округе, и мы должны отслеживать посещаемость для каждого ученика. Это то, как мы зарабатываем деньги. Моя таблица, в которой хранится отметка ежедневной посещаемости для каждого учащегося, в настоящее время насчитывает 38,9 миллиона записей. Из этого я могу очень быстро увеличить посещаемость одного студента. Мы сохраняем 4 индекса (включая первичный ключ) в этой таблице. Наш кластерный индекс - студент / дата, в котором хранятся все записи студента, упорядоченные по этому. Мы воспользовались вложениями в эту таблицу в том случае, если будет вставлена ​​старая запись для учащегося, но для наших целей это стоит того.

Что касается выбора скорости, я бы определенно воспользовался кешированием в ваших обстоятельствах.

0 голосов
/ 14 декабря 2008

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

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

Индексы в SQL Server всегда сортируются по порядку столбцов в индексе. Таким образом, индекс по [акции, дата] сначала будет сортироваться по акциям, а затем по акциям на дату. Индекс [дата, запас] сначала сортируется по дате, а затем по дате на складе.

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

Для вашей конкретной проблемы: если наиболее часто используются запросы на диапазон дат для акций, введите первичный ключ для [date, stock], чтобы данные сохранялись последовательно по дате на диске, и вы должны получить быстрый доступ. Создайте другие индексы по мере необходимости. Выполните перестроение индекса / обновление статистики после добавления большого количества новых данных.

0 голосов
/ 03 декабря 2008

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

Таблица текущего года должна сильно отличаться от этой исторической таблицы. Насколько я понял, вы планируете вставлять записи на ходу? Я бы планировал что-то другое, например, массовую вставку или что-то подобное время от времени в течение дня. Конечно, все это зависит от того, что вы хотите сделать.

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

0 голосов
/ 03 декабря 2008

План выполнения показывает, что он достаточно хорошо использует кластерный индекс, но я забыл чрезвычайно важный факт, я все еще вставляю данные! Вставка, вероятно, блокирует стол слишком часто. Есть способ увидеть это узкое место?

План выполнения, похоже, ничего не показывает о проблемах блокировки.

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

...