Skip to content

Нормализация для сокращения блокировок

Erik Darling. Normalizing To Reduce Blocking


Посыл


Я вижу множество таблиц, которые выглядят примерно так:

CREATE TABLE dbo.orders
(
order_id int NOT NULL PRIMARY KEY
DEFAULT (NEXT VALUE FOR dbo.order_id),
order_date datetime NOT NULL,
order_ship_date datetime NOT NULL,
order_total money NOT NULL,
order_tax money NOT NULL,
customer_id int NOT NULL
DEFAULT (NEXT VALUE FOR dbo.customer_id),
customer_fullname nvarchar(250),
customer_street nvarchar(250),
customer_street_2 nvarchar(250),
customer_city nvarchar(250),
customer_state nvarchar(250),
customer_zip nvarchar(250),
customer_country nvarchar(250)
);

Глядя на структуру, очевидны две большие проблемы:

  1. Столбцы заказа (order) будут принимать большое число вставок и обновлений.

  2. Одна и та же информация о заказчике будет сохраняться снова и снова.

Чем больше связанных, но не независимых данных вы храните в одной таблице, тем сложнее эффективно индексировать эту таблицу.

Лучше, но не идеально


Если следовать некоторым практическим рекомендациям и разнести столбцы с соответствующими именами в собственные таблицы, мы получим:

CREATE TABLE dbo.orders
(
order_id int NOT NULL PRIMARY KEY
DEFAULT (NEXT VALUE FOR dbo.order_id),
order_date datetime NOT NULL,
order_ship_date datetime NOT NULL,
order_total money NOT NULL,
order_tax money NOT NULL,
customer_id int NOT NULL
);

CREATE TABLE dbo.customers
(
customer_id int NOT NULL PRIMARY KEY
DEFAULT (NEXT VALUE FOR dbo.customer_id),
customer_fullname nvarchar(250),
customer_street nvarchar(250),
customer_street_2 nvarchar(250),
customer_city nvarchar(250),
customer_state nvarchar(250),
customer_zip nvarchar(250),
customer_country nvarchar(250)
);

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

Но пока не идеально - что если заказчик пожелает отправить заказ по другому адресу?

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

Лучше сформулировать таблицу клиентов следующим образом:

CREATE TABLE dbo.customers
(
customer_id int NOT NULL PRIMARY KEY
DEFAULT (NEXT VALUE FOR dbo.customer_id),
default_fullname nvarchar(250),
default_street nvarchar(250),
default_street_2 nvarchar(250),
default_city nvarchar(250),
default_state nvarchar(250),
default_zip nvarchar(250),
default_country nvarchar(250)
);

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

Тогда мы имеем таблицу EAV-данных (модель сущность-атрибут-значение), которая выглядит следующим образом:

CREATE TABLE dbo.customers_address_book
(
address_id int NOT NULL
DEFAULT (NEXT VALUE FOR dbo.address_id),
customer_id int NOT NULL,
address_type tinyint,
customer_fullname nvarchar(250),
customer_street nvarchar(250),
customer_street_2 nvarchar(250),
customer_city nvarchar(250),
customer_state nvarchar(250),
customer_zip nvarchar(250),
customer_country nvarchar(250),
CONSTRAINT pk_cab_id PRIMARY KEY (customer_id, address_id)
);

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

При таком способе моделирования данных, нам нет необходимости иметь дополнительные столбцы для хранения множества адресов. Мы просто добавляем строки, и поскольку эти данные вряд ли будут обновляться, шаблон вставки/выборки должен иметь минимальную блокировку.

Приправа


Я знаю, это ужасно. Возможно, вам придется написать соединения. Несчастный девелопер.

Конечно, это имеет больше смысла, если вы имеете дело с OLTP-нагрузкой. И, конечно же, многие из этих столбцов, вероятно, не должны быть такими длинными, но это тема совершенно другой статьи.

Когда вы имеете дело с данными для отчетов, обычно предпочтительна денормализация. Хотя, если вы составляете серьезную отчетность и используете индексы поколоночного хранения, я, вероятно, хотел бы сохранить строки максимально длинными и просто обращаться к ним по ключу в других таблицах. Фух.

Говорил я когда-нибудь, что символьные данные в базах данных были ошибкой?

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.