Wydajność wkładki wzrasta pod obciążeniem: dlaczego?

19

Mam kawałek kodu, który wykonuje wstawki do wysoce zdenormalizowanych tabel. Tabele zawierają liczby kolumn od ~ 100 do 300+. To jest SQL Server 2008 R2, działający w systemie Windows Server 2008.

Każda wstawka polega na wstawieniu do wielu tabel w ramach tej samej transakcji. Niektóre wstawki są grupowane przez NHibernate, ale niektóre nie mogą, ale wszystkie są objęte tą samą transakcją.

Kiedy wykonuję wstawki, powiedzmy 500 razy, wielokrotnie wywołując fragment kodu, który wykonuje wstawienie, otrzymuję średnio ~ 360 ms.

Dziwne jest to, że kiedy uruchamiam kod testowy jednocześnie przy użyciu 4 procesów (ten sam exe uruchamiany z 4 różnych poleceń w Windows Server 2008), wydajność wstawiania dla każdego połączenia staje się znacznie lepsza. Widzę serie, które idą tak szybko, jak 90 ms (prawie X4 szybciej). Mierzę czas wstawiania z kodu.

Ponieważ 4 procesy nic nie wiedzą o sobie, zakładam, że ma to coś wspólnego z SQL Server, ale nie mam pojęcia, dlaczego. Chciałbym wiedzieć, dlaczego tak się dzieje i czy istnieje jakakolwiek konfiguracja, która pozwoliłaby mi uzyskać taką samą wydajność, gdy wkładki nie są tak częste.

Sugestie dotyczące metod monitorowania programu SQL Server w celu zrozumienia, co dzieje się na poziomie db są równie mile widziane.

Mahonya
źródło

Odpowiedzi:

15

Jednym z możliwych powodów jest to, że cztery współbieżne procesy generują bardziej korzystny wzorzec opróżniania logów - zwykle oznacza to, że każde opróżnianie logów zapisuje więcej danych niż w przypadku pojedynczego procesu wykonawczego.

Aby ustalić, czy przepustowość / wielkość dziennika transakcji jest czynnikiem, monitoruj:

Poszukaj wewnętrznych limitów. W SQL Server 2008 R2 może istnieć maksymalnie 32 zaległe (asynchroniczne) operacje we / wy opróżniania dziennika na bazę danych w 64-bitowych wersjach (tylko 8 w 32-bitowych). Całkowity limit wielkości zaległych operacji we / wy wynosi 3840 KB.

Więcej informacji i dalsze czytanie:

Paul White mówi GoFundMonica
źródło
12

Wszystko, co mówi @PaulWhite, plus ...

Jeśli posiadasz klucze obce, każda wstawka będzie wymagała sprawdzenia w każdej tabeli, do której istnieją odniesienia. Wydaje mi się, że jesteś, bo masz tylko 360 ms, co wydaje mi się powolne.

W każdym razie sprawdzenie tych tabel jest znacznie łatwiejsze, ponieważ te dane są już w pamięci RAM, zamiast konieczności ładowania ich na dysk.

Wydaje mi się, że ładowanie danych do pamięci RAM jest znaczącą częścią twojego wykonania i że musi to nastąpić tylko raz.

Może to również być skuteczne buforowanie planu i że twoje zapytania muszą zostać skompilowane za pierwszym razem, a kolejne połączenia będą w stanie uniknąć tej fazy.

Rob Farley
źródło
Dzięki, Rob. Mój problem z wydajnością jest związany z dużą liczbą tabel używanych podczas wstawiania. Nie ma kluczy obcych, usunąłem je ze względu na wydajność, a moje wymagania dotyczące modelu i domeny pozwalają mi to zrobić. Nie ładuję danych do pamięci RAM, a moje wstawki są kształtowane dynamicznie przez przychodzące żądania, które cały czas się zmieniają. Zasadniczo niewłaściwie używam schematu gwiazda / płatek śniegu (ish) do OLTP i staram się uzyskać jak najlepszą wydajność.
mahonya
2
@mahonya, nawet jeśli nie ładujesz jawnie danych do pamięci RAM, SQL Server musi najpierw odczytać potrzebny indeks i strony danych w buforze pamięci podręcznej przed wykonaniem operacji wstawiania. Współbieżne wątki wstawiania mogą powodować rozgrzewanie pamięci podręcznej, tak że jeden wątek powoduje narzut odczytu, a drugi dostęp do danych w pamięci podręcznej.
Dan Guzman
Dzięki @DanGuzman - i tak, mahonya, istnieje duża szansa, że ​​pamięć podręczna zostanie ładnie rozgrzana. Sprawdzałbym twoje oczekiwania, aby sprawdzić, czy to fizyczne we / wy powoduje wąskie gardło.
Rob Farley,
Dzięki @DanGuzman zgodził się, przyspieszenie pamięci podręcznej indeksu db jest czymś, co przyzwyczaiłem się do postgresów Prawdopodobnie źle zrozumiałem dane Roba.
mahonya
-3

niektóre serwery / cpus / os pamiętają wzorce. jak pamięć podręczna.

Ponieważ robisz to samo 4 razy, jestem pewien, że istnieją sposoby, aby skrócić narożniki. Domyślam się, że pierwszy sposób, w jaki to robisz, traktuje to jako jeden długi proces (przykład 1), ale w drugą stronę widzi ponownie użyty kod i uruchamia go jak pamięć podręczną (przykład 2) lub może być pierwszym procesem, aby zmieścić wszystko w (ram example3).

przyklad 1: 0111110000110111110000111011111000011110111110000

przyklad2: 0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

example3: 0111110000011111000001111100000111110000 example3: loop: 0111110000

Wiem, że serwer Ubuntu robi to z powtarzającymi się zapytaniami mysql. Mogę zapisać je w pamięci podręcznej, chociaż tak naprawdę jedyną różnicą w czasie jest 10-40 mm, ale sumuje się. Kiedy byłem w szkole, były zajęcia, które pokazały, że musisz sprawić, aby programy (perl / php) używały tej pamięci podręcznej, aby były szybsze.

Ale może zależeć od programu, w jakim języku, w jakiej wersji jest skompilowany lub w jaki sposób został zaprogramowany.

Bryku
źródło