2010-03-09 3 views
3

Фон: Профессиональный инструмент разработчика. SQL/DB любитель.Удаление дублирования строк в базе данных SQL Server 2008

Установка: .NET 3.5 WinForms приложения говорить с MS SQL Server 2008.

Сценарий: я заполнение базы данных с информацией, извлеченной из большого количества файлов. Это составляет около 60 М записей, каждый из которых имеет связанное с ним сообщение произвольного размера. Мой первоначальный план состоял из nvarchar (max) поля в записи для хранения сообщений, однако после выполнения тестового прогона в подмножестве данных это сделало базу данных слишком большой (экстраполируется на недопустимый 113 ГБ). Запустив несколько запросов в этом первоначальном наборе тестовых данных (база данных 1,3 ГБ), я обнаружил, что произошло значительное дублирование сообщений, и мы могли бы использовать это, чтобы уменьшить данные сообщений примерно на одну шестую. Я пробовал и думал о нескольких подходах к достижению этого, но ни один из них не является удовлетворительным. Я обыскал в течение нескольких дней, но либо: а) не кажется, что это хороший ответ (маловероятно), или б) я не знаю, как выразить то, что мне нужно достаточно хорошо (скорее).

Подходы, рассмотренные/пробовали:

  1. Массовые вставки сообщений в записи с NVARCHAR (макс) поле. - обнаружено, что у них слишком много избыточности.
  2. Придерживайтесь этого столбца сообщения, но найдите способ заставить базу данных «сжать» сообщения. - не знаю, как это сделать.
  3. Добавить таблицу сообщений для уникальных сообщений с ключом на идентификаторе, в котором находится основная запись (ы). - в то время как работа в принципе, реализация уникальности оказывается болезненной и страдает от замедления по мере добавления большего количества сообщений.
  4. Выполните дублирование на клиенте. - требует, чтобы все сообщения были отправлены клиенту для каждого сеанса населения. Это не масштабируется, так как им нужно будет вписываться в память.
  5. Добавьте в таблицу сообщений дополнительный (индексированный) хэш-столбец и отправьте сообщения с соответствующим (локально сгенерированным) хэш-значением. Найдите это, чтобы сузить сообщения, которые на самом деле нуждаются в тестировании. - сложный, должен быть лучший способ.

Этот третий подход представляет собой создание таблицы словаря строк. После нескольких итераций по этой идее я закончил с следующее:

  1. База данных содержит таблицу сообщений, которая сопоставляет (автоматический назначенный) INT ID первичный ключ к NVARCHAR (макс) сообщение ,
  2. Клиент отправляет сообщения и отправляет несколько записей для вставки в хранимую процедуру.
  3. хранимая процедура перебирает партии входящих записей, и для каждого сообщения:

    я. Таблица словаря сообщений проверяется (SELECT) для существующего экземпляра сообщения.

    ii. Если найдено, запомните идентификатор существующего сообщения.

    iii. Если не найден, вставьте новую запись сообщения, запомните идентификатор новой записи (OUTPUT).

  4. Идентификаторы для всех сообщений (старые и новые) возвращаются в качестве результата результата, установленного в процедуре.

  5. Клиент создает основные записи таблицы с записями (int внешних ключей) для сообщений, заполненных идентификаторами, возвращаемыми процедурой.

Вопросы:

  1. Поиск существующих сообщений становится все медленнее и медленнее, так как количество сообщений растет, становится ограничивающим фактором.
  2. Я попытался проиндексировать (UNIQUE) столбец сообщений, но вы не можете индексировать nvarchar (max) column.
  3. Я просмотрел возможности полнотекстового поиска MS SQL Server 2008, но для меня это кажется излишним.
  4. Я думал о попытке MERGE в пакетах сообщений, но я не вижу способа легко получить соответствующий список идентификаторов (старый и новый, в правильном порядке), чтобы вернуть клиенту ,

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

Итак, мой вопрос: Каков правильный подход?

Любая помощь очень ценится.

Сэм

+0

Каковы ваши целевые показатели производительности и ресурсов? Как быстро вам нужно вставлять записи? Почему 113 ГБ слишком много данных? Вам действительно нужно использовать nvarchar (max)? Не могли бы вы использовать меньший столбец и помещать несоответствующие данные в специальную таблицу (которая закончилась бы меньшим количеством строк)? –

+0

Да, я понимаю, что я немного расплывчато о цели. Население не * действительно * проблема, так как это одноразовая (плюс текущие небольшие обновления). Тем не менее, тестовый прогон занял около часа, поэтому, предполагая линейное масштабирование, мы смотрим около 100 часов. Я бы хотел, чтобы это было быстрее, так как это заставляло репопуляцию при разработке системы довольно дорого. Некоторые из сообщений превышают 4000-символьный предел экспансивного размера varchar, поэтому теоретически мне нужно «max». Отдельная таблица для несоответствующих сообщений - интересная идея, хотя ... – Gaspode

+0

В качестве примечания стороны, max 'varchar' составляет 8000; Максимальный размер nvarchar составляет 4000. –

ответ

1

Существует два практических аспекта (и причин) нормализации: чувствительность к размещению данных (и соответствующему бланку обслуживания) и эффективности.

Что касается чувствительности, то один вопрос, который вам необходимо рассмотреть, по крайней мере, от абстрактная перспектива проектирования БД - это то, действительно ли данные дублируются. Хотя у вас могут быть два сообщения, которые имеют идентичные данные, они могут не представлять «то же самое» в действительности. Реальный вопрос: Имеет ли тот факт, что два сообщения имеют один и тот же текст, делает их одним и тем же сообщением? Иными словами, считая, что сообщение A и сообщение B имеют один и тот же текст, хотите ли вы, чтобы изменение сообщения A отражалось в сообщении B?

Если ваш ответ «да», то ваш строковый словарь - правильный подход. Если нет, то вы не действительно имеют дубликаты данных, просто данные, которые выглядят одинаково, но нет.

С точки зрения производительности я, вероятно, думаю, что строковый словарь с дополнительным хешем сообщения будет лучшим подходом; Я не думаю, что это действительно так сложно, как вы считаете. Стандартные алгоритмы хэширования доступны практически на каждом языке (включая T-SQL), и я бы не стал рассматривать возможность столкновений или даже распределение хэш-значений в этом сценарии, поскольку вы используете его только как " hint ", чтобы ускорить выполнение запроса.

+0

Прохладный, ответ теории db :) Так как я использую базу данных только для анализа данных, я бы рассматривал сообщения неизменяемыми, и, следовательно, ваши A и B * - одно и то же. Интересная перспектива. – Gaspode

2

Сэм, я думаю, что ты на что-то с подход # 5. И я действительно не думаю, что это было бы так сложно реализовать, как вы думаете. Локально созданный хэш сообщений легко производить, и он значительно ускорит все поиски (в базе данных).

Конечно, если действительно нужны сообщения nvarchar(max). Если вы можете уйти с меньшим пространством (512, я думаю, для), чем вы могли бы установить ограничения уникальности в SQL и индексе в столбце, которые сделали бы поиск намного быстрее - определенно моя рекомендация, если вы считаете, что можете сократить длину сообщения ,

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

1

У вас было решение в вашей статье.С большими данными, как NVARCHAR (макс) необходимо уменьшить поиск набор - как вы сказали:

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

Это способ решить эту проблему.

Если вы не хотите иметь дело с хэшами, сделайте первые 150 символов или так хэш (например, varchar (150)), используйте это, чтобы уменьшить поиск дубликатов. Это будет не так уникально, как хеш, но в зависимости от ваших данных он может работать. (Вы также можете использовать 75 первых символов и 75 последних символов.) Некоторые тесты данных должны показывать вам, какие области для подстроки являются наиболее уникальными.

Смежные вопросы