Дизайн таблицы для «изолированных» таблиц, чтобы избежать блокировки?

#sql-server #database #database-design

#sql-server #База данных #database-design

Вопрос:

У меня есть приложение, в котором есть группы пользователей, которые редко никогда не видят или не взаимодействуют с данными друг друга, даже если они находятся в одних и тех же таблицах. Фактически все они могут работать с отдельными базами данных SQL Server 95% времени. Но я не хочу иметь отдельную базу данных для каждой, потому что это создает свои собственные проблемы (например, в остальных 5% случаев).

Как я могу спроектировать так, чтобы никогда не было (или минимальной) «блокировки между группами», а запросы выполнялись быстро? То есть пользователи «изолированы» друг от друга, в идеале никогда не нужно блокировать один и тот же ресурс (индекс, ключ и т. Д.)?

Например, представьте таблицу для хранения «заказов на продажу»:

 create table SalesOrder (
    UserGroupId int not null foreign key references UserGroup(UserGroupId),
    SalesOrderId int not null,
    DatePlaced datetime not null,
    primary key (UserGroupId, SalesOrderId)
)
  

Изначально у меня был только первичный ключ в SalesOrderID в качестве идентификатора, но теперь я регулярно вижу вставку, которая блокирует первичный ключ, заставляя ждать вставку от пользователя в другой группе. Даже несмотря на то, что почти никогда не будет запроса, который сканировал бы всю таблицу или имел какие-либо ложные результаты из-за наличия или отсутствия записи из «другой группы». Так что все это кажется очень расточительным.

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

Аналогично представьте запросы, включающие DatePlaced . Группе A нужны только «их» записи, поэтому должен ли индекс быть (UserGroupId, DatePlaced)? Чтобы избежать необходимости бесполезного сканирования заказов на продажу других пользователей.

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

Таким образом, таблица «элементов» в порядке (1 .. много) будет:

 create table SalesOrderItem(
    GroupId int not null foreign key references UserGroup(UserGroupId),
    SalesOrderId int not null,
    SalesOrderItemId int not null,
    primary key(GroupId, SalesOrderItemId),
    foreign key (GroupId, SalesOrderId) references SalesOrder(UserGroupId, SalesOrderId)
)
  

Надеюсь, это имеет смысл, и спасибо за вашу помощь!

Комментарии:

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

2. Спасибо, Бен! Похоже, что я вставляю запись, которая запускает ограничение идентификатора для создания нового значения PK. Но это блокирует всю таблицу на время транзакции, в которую была завернута вставка, что, к сожалению, может занять довольно много времени. Что затем приводит к ожиданию инструкций «select». Итак, смысл в том, чтобы заставить SQL Server блокировать только «часть» таблицы, а не «всю» таблицу для всех операций. Это значительно уменьшило бы конфликт. Действительно ли редизайн ключа делает это ядром моего вопроса?

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

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

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