Лучший способ индексировать эту очень большую таблицу

некоторые ldap серверы позволяют анонимную привязку. затем [afaik], которые Вы не должны обеспечивать, связывают пароль.

4
задан 24 November 2009 в 07:12
7 ответов

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

Фрагментация является главным образом проблемой для сканирований, меньше для ищет. Фрагментация оказывает большое влияние на чтение-aheads и ищет, не используют, ни должны считать aheads. Нефрагментированный индекс с плохим выбором столбца будет всегда работать хуже, чем 99%-й индекс фрагмента с хорошим, применимым, столбцами. Если Вы имели, описал DW, сообщив о запросах стиля, которые сканируют таблицы затем, я был бы, имел, рекомендуют фокусироваться на устранении фрагментации, но для загрузки Вы описываете это, имеет больше смысла фокусироваться на эффективном (покрытие), ищет и (небольшие) сканирования диапазона.

Учитывая, что Вы - схема доступа, всегда управляется @userId, это должно быть крайним левым столбцом в кластерном индексе. Я также добавил бы setOn как второй столбец в кластерном индексе, потому что он добавляет некоторое предельное значение на большинстве запросов (я говорю крайний, потому что @userId таким образом выборочный, в худшем случае 90 записей от 90 миллиметров., то, что дополнительная фильтрация, добавленная @setOn, не очень важна). Я woudldn't добавляют любого не кластерный индекс от запросов, которые Вы описываете, нет никакой потребности ни в ком.

Единственной проблемой является удаление старых записей (хранение этих 30 дней). Я рекомендовал бы против использования вторичного индекса NC удовлетворить это. Я развернул бы еженедельную схему выделения разделов с раздвижным окном, посмотрите, Как Реализовать Автоматическое Раздвижное окно в Разделенной таблице на SQL Server 2005. С этим решением старые записи удалены переключателем раздела, который является просто самым эффективным возможным путем. Ежедневную схему выделения разделов удовлетворила бы требование хранения этих 30 дней более точно и возможно стоит попробовать и протестировать. Я смущаюсь рекомендовать 30 разделов непосредственно, потому что Вы описываете некоторые запросы, которые имеют потенциал для поиска конкретного @userId записи в каждом разделе, и 31 раздел может создать проблемы производительности под большой нагрузкой. Протестируйте и измерьте обоих лучше.

5
ответ дан 3 December 2019 в 02:24
  • 1
    Привет, Remus. Это верно, что Вы говорите - " Фрагментация является главным образом проблемой для сканирований, меньше для ищет " Но что относительно стоимости фактического расщепления страницы, когда посредническая запись вставляется? Я понимаю, что эта стоимость очень высока. Рассмотрение, что большинство моих ВСТАВОК собирается вызвать расщепление страницы, isn' t это основная проблема? (Простите мне если I' m недоразумение чего-то, потому что I' m все еще новичок в этом поле). –  niaher 24 November 2009 в 04:57
  • 2
    ' Очень high' относительно. Выше, чем вставляют в конце таблицы, уверенной. Но we' ре, только говоря 3 миллиметра. вставляет день, который равняется 35 в секунду. Даже с 10x скачок не является точно высоким показателем. Расщепления страницы и другие тонкости становятся релевантными на уровнях тысяч вставок в секунду. –  Remus Rusanu 24 November 2009 в 05:18
  • 3
    Ничего себе, спасибо. Это - вероятно, самая полезная/воодушевленная информация I' ve получен в течение многих дней. Однако как мое окончательное решение, я придумал совершенно другой дизайн. Отправит его здесь скоро. –  niaher 24 November 2009 в 05:34
  • 4
    Расщепления страницы также увеличивают сумму сгенерированного журнала транзакций: sqlskills.com/BLOGS/PAUL/post/… –  SuperCoolMoss 24 November 2009 в 18:42

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

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

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

WHERE setOn > @setOn AND userId = @userId

Или когда Вы возвращаете целый месяц:

WHERE setOn BETWEEN @setOnBegin AND @setOnEnd AND userId = @userId

Ваш новый дизайн схемы, без разделения был бы похож на это:

-- Stub table for foreign key
CREATE TABLE Users
(
 [userId] [uniqueidentifier] NOT NULL
  CONSTRAINT PK_Users PRIMARY KEY NONCLUSTERED
  CONSTRAINT DF_Users_userId DEFAULT NEWID(),
 [userName] VARCHAR(50) NOT NULL
)
GO

CREATE TABLE DiaryEntries
(
 [userId] [uniqueidentifier] NOT NULL
  CONSTRAINT FK_DiaryEntries_Users FOREIGN KEY REFERENCES Users,
 [setOn] [datetime] NOT NULL
  CONSTRAINT DF_DiaryEntries_setOn DEFAULT GETDATE(),
 [entry] [nvarchar](255) NULL,
 CONSTRAINT PK_DiaryEntries PRIMARY KEY CLUSTERED (setOn, userId)
)
GO

После того, как Вы получите ту работу, необходимо добавить разделение. Для этого запустите с Этого сообщения в блоге для некоторой теории. Затем начните читать это техническое описание MSDN. Отчет записан на 2005, и были улучшения раздела в 2008, что я не занялся расследованиями, таким образом, решение могло бы быть простым в 2008.

6
ответ дан 3 December 2019 в 02:24
  • 1
    Привет Justin.Спасибо за ответ. Я смотрел на ссылки, которые Вы дали мне - очень полезный. Так, как мне нравится Ваш совет относительно разделения, я вижу проблему с наличием индекса на (setOn, идентификатор пользователя). Вещь - это, так как мы не указываем точное значение setOn, а скорее диапазон, набор результатов от (setOn > @setOn), будет огромно. Нахождение корректного идентификатора пользователя от этого набора результатов будет очень дорогим, так как нет никакого специального порядка к тому, как значения идентификатора пользователя расположены (если, конечно, значения setOn не идентичны). Исправьте меня, если я неправ. –  niaher 22 November 2009 в 16:08
  • 2
    Niaher, лучший способ сказать наверняка состоит в том, чтобы загрузить некоторые данные тестирования и посмотреть на предполагаемые и фактические планы запросов. Если это просто выбирает разделы и делает кластерный индекс, ищут, Ваш запрос почти так оптимален, как это может добраться. Это, конечно, если нет более оптимальный план разделения/кластеризации. Вы могли бы хотеть экспериментировать с условным индексом (индекс с где пункт) на просто идентификаторе пользователя для диапазона дат идет, большинство Ваших запросов. –  Justin Dearing 22 November 2009 в 16:42

Не здесь для критикования решения, ни - я имеющий возможность делать так, поскольку я не знаю достаточно о проблеме. Вот моя обратная связь:

  • Если единственная вещь Ваш не довольный использует слишком много дискового пространства из-за размера строки, проверьте редкие столбцы Таким образом, все пустые указатели не занимают так много места!
  • Наличие внешних ключей собирается замедлить Ваши вставки значительно, Вы протестировали это?
2
ответ дан 3 December 2019 в 02:24

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

Поэтому строки должны быть заказаны в хронологическом порядке

Поэтому setOn должен быть первой частью первичного ключа. - или, идеально, добавляет 'postId' столбец, который является просто целым числом что автоинкременты самим

Если Вы не захотите отправленный столбец, то первичный ключ будет (setOn, идентификатор пользователя), иначе он может просто быть отправлен.

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

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

Индекс может быть любым стандартным B-деревом, красно-черным деревом, индексом, независимо от того, что идет с Вашей базой данных.

Вставку немного замедлит вставка в индекс, но не слишком много. Древовидные структуры довольно хороши в обработке случайных вставок.

Так как индекс UserId основан на наборе UserIds, который является устойчивым множеством, дерево должно быть довольно стабильным и не нуждаться в слишком большом изменении баланса: просто вершины в конце изменятся, поскольку записи журнала добавлены и очищены, который действительно не изменит форму дерева слишком много.

1
ответ дан 3 December 2019 в 02:24

Я не поклонник Вашего нового решения. Это просто собирается представить новые проблемы, крупнейшее существо, которое ОБНОВЛЕНИЯ (обычно) медленнее, чем, ВСТАВЛЯЕТ, и создайте больший риск для блокирования, когда обновления происходят.

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

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

К сожалению, значение по умолчанию SQL обычно 0 (что означает то же как 100), что означает, что все страницы абсолютно полны, который вызывает много расщеплений страницы. Многие люди рекомендуют значение 90 (10%-е свободное пространство в каждой странице данных). Я не могу сказать Вам, каков идеал для Вашей таблицы был бы, но если Ваш ультрапараноик о расщеплениях страницы, попробуйте 75 или еще меньше, если можно сэкономить дополнительное дисковое пространство. Существуют некоторые счетчики perfmon, которые можно контролировать для наблюдения за расщеплениями страницы, или Вы могли выполнить запросы, чтобы сказать Вам свободное пространство процента в каждой странице данных.

Относительно специфических особенностей индексов на Вашей таблице (исходная версия), я рекомендовал бы кластерный индекс на ([идентификатор пользователя], [setOn]), по причинам, что Remus упомянул.

Вам также будет нужен некластеризованный индекс на ([setOn]) так, чтобы Ваш "удалили старые записи" запрос, не должен делать полного сканирования таблицы для нахождения всех старых записей.

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

Править: Некоторые предварительные вычисления на предполагаемом fillfactor для этой таблицы.

Для каждого пользователя, 3 новых записей в день, сохранил 30 дней, таким образом, ~90 общих записей. Принятие Вас делает ежедневную чистку всех записей, более старых, чем 30 дней (только в противоположность чистке каждые 30 дней), затем Вы только добавляете/удаляете меньше чем 5% записей ежедневно.

Таким образом, fillfactor 90 (10%-е свободное пространство на каждой странице) должен быть более, чем достаточным.

Если бы Вы только производите чистку ежемесячно, то Вы позволили бы почти 60 дням сложить перед удалением самых старых 30 что означает, что Вам было бы нужно что-то как 50% fillfactor.

Я настоятельно рекомендовал бы ежедневную чистку.

Редактирование 2: После дальнейшего соображения некластерный индекс на [setOn] не может быть достаточно выборочным, чтобы использоваться Вашим запросом чистки (единственный день является 1/30 или 3,3% строк, который является правильным на краю "полезных"). Это могло бы просто сделать сканирование кластерного индекса так или иначе, даже если индекс существует. Вероятно, стоящий тестирования и с и без этого дополнительного индекса.

1
ответ дан 3 December 2019 в 02:24

Я предлагаю:

  1. Кластерный индекс на идентификаторе пользователя
  2. Некластеризованный Закрывающий индекс на seton и записи или просто некластерном индексе на seton
0
ответ дан 3 December 2019 в 02:24

Один способ решить это состоит в том, чтобы иметь таблицу в течение каждого дня.

С таблицей 3M записи это не проблема, имеющая кластерный индекс на идентификаторе пользователя и seton. Ваше время вставки было бы намного ниже.

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

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

0
ответ дан 3 December 2019 в 02:24

Теги

Похожие вопросы