Уникальный индекс SQL Server по проблеме nvarchar

У меня есть таблица SQL Server со столбцом nvarchar (50). Этот столбец должен быть уникальным и не может быть PK, так как другой столбец является PK. Поэтому я установил для этого столбца некластеризованный уникальный индекс.

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

Почему nvarchar не работает, а bigint работает? Как я могу добиться того же, используя nvarchar (50) в качестве типа данных?


person TomTee    schedule 01.05.2014    source источник
comment
Не могли бы вы просто добавить уникальное ограничение и индекс к этому столбцу? Насколько велик стол?   -  person Jane S    schedule 02.05.2014
comment
Не знаю, почему происходит блокировка. Но могли бы вы поместить значения в другую таблицу и просто использовать ссылку на внешний ключ?   -  person Gordon Linoff    schedule 02.05.2014
comment
Я забыл сказать, что у меня есть уникальный индекс в столбце nvarchar (50), я отредактирую свой запрос   -  person TomTee    schedule 02.05.2014
comment
Как могла бы помочь другая таблица, если мне все равно нужно будет делать вставки и выборки для этой таблицы?   -  person TomTee    schedule 02.05.2014
comment
Какая изоляция вам нужна для вашего SELECT? Вам не нужны незафиксированные строки? Или можно включить их в свои результаты?   -  person Clockwork-Muse    schedule 02.05.2014
comment
Мне нужны только зафиксированные строки, без грязных данных.   -  person TomTee    schedule 02.05.2014


Ответы (3)


В конце концов, тайна раскрыта! Думаю, довольно глупая ситуация ..

Проблема заключалась в операторе выбора. В предложении where отсутствовали кавычки, но из-за дьявольского совпадения существующих данных были только числа, выбор не давал сбоев, а просто не выполнялся до тех пор, пока вставки не зафиксированы. Когда были вставлены первые буквенно-цифровые данные, оператор select начал давать сбой: «Ошибка преобразования типа данных nvarchar в числовой»

например, вместо

SELECT [my_nvarchar_column]  
FROM [dbo].[my_table]  
WHERE [my_nvarchar_column] = '12345'

оператор выбора был

SELECT [my_nvarchar_column]  
FROM [dbo].[my_table]  
WHERE [my_nvarchar_column] = 12345

Я предполагаю, что было выполнено тихое приведение, уникальный индекс не использовался, что привело к блоку. Исправлен оператор, и теперь все работает как положено.

Спасибо всем за помощь и извините за довольно глупую проблему!

person TomTee    schedule 02.05.2014

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

У вас может быть случай использования покрывающего индекса, см. Предыдущий вопрос re: охватывающий индекс

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

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

ДОБАВЛЕН

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

ДОБАВЛЕН

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

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

person Gary Walker    schedule 01.05.2014
comment
Изменение индекса на кластеризованный, а PK на некластеризованный, дает тот же результат. Я все еще не могу выбрать на основе этого столбца. - person TomTee; 02.05.2014
comment
Да, необходима сериализуемая транзакция. Эти большие вставки случаются нечасто, но в течение этого времени таблица должна быть доступна. Нет нерабочее время, в которое можно было бы сделать вставки. Все вставки должны быть неудачными или успешными. Полагаю, я могу использовать ожидающую таблицу, но я также должен поддерживать данные в этой таблице (например, после удаления), иначе уникальное ограничение не дало бы результата. Но это кажется большим усилием. - person TomTee; 02.05.2014
comment
Что ж, это не просто атомарность, поскольку в случае сбоя вставки должен произойти откат для других данных, ранее обработанных в той же транзакции. Я попробую решение с отложенной таблицей в качестве последнего, но более безопасного варианта, хотя я предполагаю, что мне следует поддерживать одни и те же данные между двумя таблицами и вставлять новые строки небольшими партиями. Спасибо за предложение. - person TomTee; 02.05.2014

Вы можете добавить подсказку NOLOCK (также известную как READUNCOMMITTED) в свой запрос. Это позволит выполнить «грязное чтение» уже вставленных данных.

e.g.

SELECT [my_nvarchar_column] FROM [dbo].[locked_table] WITH (NOLOCK)

Взгляните на лучшее объяснение здесь:

http://www.mssqltips.com/sqlservertip/2470/understanding-the-sql-server-nolock-hint/

И раздел READUNCOMMITTED здесь:

http://technet.microsoft.com/en-us/library/ms187373.aspx

person uhleeka    schedule 01.05.2014
comment
OP специально вставляется в SERIALIZABLE транзакцию, поэтому я бы не решился предложить что-то, что по существу игнорировало бы транзакцию (то есть, что строки могли бы исчезнуть). Вероятно, нам понадобится дополнительная информация из OP ... - person Clockwork-Muse; 02.05.2014
comment
Сериализуемая транзакция является обязательным требованием. - person TomTee; 02.05.2014