Jak uzyskać wstawianie i / lub aktualizowanie SQL, aby nie blokować całej tabeli na MS SQL Server

13

Bardzo początkujący w pracy z DB, więc doceń swoją cierpliwość w kwestii podstawowego pytania. Korzystam z programu SQL Server 2014 na moim komputerze lokalnym i mam małą tabelę oraz podstawową aplikację kliencką do testowania różnych metod. Dostaję coś, co wydaje się być blokadą tabeli podczas obu INSERT INTOi UPDATEinstrukcji. Klient jest aplikacją ASP.NET z następującym kodem:

OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();

Uruchamiam ten kod, a następnie uruchamiam ze studia zarządzania SELECT * FROM LAYOUTSv2. W obu przypadkach, gdy wątek klienta jest wstrzymany (tj. Przed zatwierdzeniem / wycofaniem), zapytanie SELECT zawiesza się do momentu zatwierdzenia / wycofania.

Tabela ma pole LAYOUTS_key przypisane jako klucz podstawowy. W oknie właściwości pokazuje, że jest unikalny i klastrowany, z dozwolonymi blokadami stron i blokad wierszy. Ustawienie eskalacji blokady dla tabeli to Wyłącz ... Próbowałem obu pozostałych ustawień Tabeli i AUTO bez zmian. Próbowałem SELECT ... WITH (NOLOCK)i to natychmiast zwraca wynik, ale jak to dobrze ostrzega tutaj i innych miejscach, nie jest to, co powinienem robić. Próbowałem ROWLOCKwskazać zarówno na oświadczenia, jak INSERTi na UPDATEoświadczenia, ale nic się nie zmieniło.

Zachowanie, którego szukam, jest następujące: przed zatwierdzeniem INSERTkwerendy z innych wątków czytają wszystkie wiersze z wyjątkiem tego, który jest INSERTedytowany. Przed zatwierdzeniem UPDATEzapytań z innych wątków przeczytaj początkową wersję edytowanego wiersza UPDATE. Czy jest jakiś sposób, żeby to zrobić? Jeśli muszę podać inne informacje w celu wyjaśnienia mojego przypadku użycia, daj mi znać. Dzięki.

John Riehl
źródło
3
Nawiasem mówiąc, WHERE LAYOUTS_key='" + newkey + "'jest to kompletne „nie” z różnych powodów, w tym wstrzykiwania SQL, należy stosować sparametryzowane zapytania.
Martin Smith
1
@MartinSmith Dzięki za informacje na ten temat ... nigdy nie słyszałem ani o sparametryzowanych zapytaniach, ani o atakach SQL Injection.
John Riehl
@JohnRiehl, re: ataki iniekcyjne, wyobraź sobie, że Twój użytkownik ustawił opcję newkeysomething';DELETE FROM LAYOUTSv2 --”. Aktualizacja zakończy się pomyślnie, a następnie opróżni tabelę, ponieważ użytkownik manipulował zapytaniem, wstawiając apostrof. Zwykle sparametryzowane zapytanie wygląda mniej więcej tak UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?, po czym osobno przypisujesz wartości do ?parametru w swoim kodzie.
Daniel Hutmacher

Odpowiedzi:

10

Możliwe, że nie blokuje „całego stołu”.

Blokuje wiersz w tabeli, ale SELECT * FROM LAYOUTSv2próbujesz odczytać cały stół, więc koniecznie jest blokowany przez tę blokadę.

W przypadku wstawiania możesz jedynie wskazać READPASTwskazówkę, aby pominąć zablokowany UPDATEwiersz - nie da to jednak pożądanego rezultatu w przypadku (ponownie pominie wiersz, nie czytając początkowej wersji wiersza).

Jeśli skonfigurujesz bazę danych do odczytu zatwierdzonej izolacji migawki , da to pożądany efekt w obu przypadkach (kosztem większego wykorzystania tempdb)

Martin Smith
źródło
Zmieniłem „Czyta zatwierdzoną migawkę na” na Prawdę, a teraz działa idealnie bez żadnych podpowiedzi. Dzięki! Jedna kontynuacja ... Pozostawiłem „Zezwalaj na izolowanie migawek” na Fałsz ... czy to w porządku? Dzięki.
John Riehl
@JohnRiehl - Tak, jeśli nie używasz wyraźnie SNAPSHOTizolacji, najlepiej pozostaw ją wyłączoną, a następnie włącz ją, jeśli później zdecydujesz, że będzie to dla Ciebie przydatne.
Martin Smith
7

Instrukcje wstawiania i aktualizacji powinny tworzyć blokady na poziomie wiersza. Jednak gdy liczba blokad w dowolnej transakcji wynosi 5000 lub więcej, następuje eskalacja blokady i tworzy ona blokadę na poziomie tabeli. Patrz poniżej.

https://technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspx

Suraj
źródło
Nie dotyczy tego pytania, ponieważ zarówno INSERT, jak i UPDATE piszą jeden wiersz
Martin Smith