Дизайн базы данных: новая таблица против новых столбцов

38

(Это было предложено сделать репостом из StackOverflow)

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

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

Первая таблица представляет собой запись просмотров страниц (в настоящее время 2 миллиона записей)

- мне бы
- Айпи адрес
- время просмотра
- метка времени созданного
- свидание

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

дополнительные поля будут для отслеживания точки происхождения (например, источник / среда / кампания Google Analytics)

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

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

Цените обратную связь - можете добавить больше, если это необходимо

cgmckeever
источник

Ответы:

29

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

В общем случае вертикальное разбиение полезно, если вы будете запрашивать эти новые столбцы не так часто и в отличие от других столбцов исходной таблицы. Поместив эти столбцы в другую таблицу, которая использует тот же PK, что и существующая таблица, вы можете запросить ее напрямую, когда захотите эти новые столбцы, и получить гораздо большую пропускную способность, поскольку у вас будет гораздо больше строк на страницу на диске для этой новой таблицы поскольку все столбцы из исходной таблицы не будут сидеть в этих строках. Однако, если вы всегда будете запрашивать эти столбцы вместе со столбцами в исходной таблице, вертикальный раздел не будет иметь особого смысла, поскольку для их получения вам всегда будет необходимо внешнее соединение. Страницы из таблиц на диске попадают в буферный пул СУБД независимо друг от друга, предварительно не объединяясь, и поэтому это соединение должно происходить при каждом выполнении запроса, даже если данные закреплены в пуле буферов. В этом сценарии создание из них столбцов NULLABLE в исходной таблице позволило бы механизму хранения СУБД эффективно хранить их при NULL и исключить необходимость объединения при извлечении.

Мне кажется, что ваш вариант использования является последним, и добавление их как NULLABLE в исходную таблицу - это путь. Но, как и во всем остальном в проектировании баз данных, это зависит от ситуации, и для принятия правильного решения вам необходимо знать ожидаемую рабочую нагрузку и то, от чего зависит правильный выбор. Одним хорошим примером правильного варианта использования вертикального разделения может служить панель поиска людей, где в вашем приложении есть очень редко заполняемая информация о человеке, по которому кто-то может искать, но редко делает. Если вы поместите эту информацию в другую таблицу, у вас есть несколько хороших вариантов для производительности. Вы можете написать поиск так, чтобы у вас было 2 запроса - один, который использует основную, всегда заполненную информацию для поиска (например, фамилия или ssn), и тот, который внешний, присоединяется к очень редко заполняемой информации только тогда, когда она запрашивается для поиска. Или вы можете воспользоваться оптимизатором СУБД, если он достаточно умен, чтобы распознавать для заданного набора переменных хоста, что внешнее соединение не требуется и не будет его выполнять, и, следовательно, вам нужно всего лишь создать 1 запрос.

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

Тод эверетт
источник
Мне непонятно, что вы имеете в виду под «Тем не менее, если вы всегда будете запрашивать эти столбцы вместе со столбцами в исходной таблице, тогда вертикальный раздел не будет иметь большого смысла, так как вам всегда потребуется внешнее соединение, чтобы получить их». вам нужно будет выполнить внешнее объединение только тогда, когда вы хотите, чтобы первичные столбцы были доступны или нет, если вторичные столбцы доступны, в противном случае вы бы использовали INNER JOIN, и в большинстве случаев это было бы выгодно (уменьшая количество строк, на которые вы просматриваете). ).
Jmoreno
Спасибо за всю помощь здесь. Я действительно добавил добавление полей, но, обдумав это, я увидел, что у меня должна быть пара других таблиц, чтобы лучше идентифицировать все. В конце концов он пришел к посетителю visitor_visits (который имеет visitor_id и содержит источник) page_views (который имеет vistor_id и visitor_visit_id), поскольку я хочу точно знать, какой page_view относится к посещению, я добавил эту ссылку. Я боролся с этим немного, но я думаю, что это было правильное решение
cgmckeever
10

Лично я склоняюсь к добавлению столбцов в существующую таблицу. Новый стол на самом деле ничего не покупает:

  • вы на самом деле не экономите много места, потому что значения NULL в исходной таблице не занимают места, а новой таблице нужен какой-то идентификатор, который в любом случае компенсирует любую экономию
  • ваши запросы становятся более сложными ... where newcolumn is not nullстановитсяleft outer join

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

Аарон Бертран
источник
Поскольку таблица в настоящее время не является широкой (основываясь на вашем описании), и эти данные не сделают ее слишком широкой, я бы согласился.
HLGEM
4

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

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

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

Кейд Ру
источник