7

Mamy bardzo dużą bazę danych WriteDB, która przechowuje surowe dane handlowe i używamy tej tabeli do szybkiego zapisu. Następnie za pomocą skryptów sql importuję dane z WriteDB do ReadDB w stosunkowo tej samej tabeli, ale rozszerzonej o dodatkowe wartości + relacje dodane. Skrypt importowania wygląda następująco:INSERT INTO idzie znacznie wolniej z czasem w SQL Server 2012

TRUNCATE TABLE [ReadDB].[dbo].[Price] 
GO 
INSERT INTO [ReadDB].[dbo].[Price] 
SELECT a.*, 0 as ValueUSD, 0 as ValueEUR 
from [WriteDB].[dbo].[Price] a 
JOIN [ReadDB].[dbo].[Companies] b ON a.QuoteId = b.QuoteID 

Początkowo jest to około 130 mil. wiersze w tej tabeli (~ 50 GB). Każdego dnia niektóre z nich dodawały, niektóre z nich zmieniały się, więc teraz decydujemy się nie komplikować logiki i po prostu ponownie zaimportować wszystkie dane. Problem polegający na tym, że z jakiegoś powodu ten skrypt działa dłużej i dłużej na prawie takiej samej ilości danych. Pierwsze uruchomienie trwa ~ 1h, teraz jest już zajęta 3h

Również SQL Server po imporcie działa niezbyt dobrze. Po zaimportowaniu (lub podczas niego), jeśli próbuję uruchomić różne zapytania, nawet najprostsze często zawodzą z błędami limitu czasu.

Jaki jest powód takiego złego zachowania i jak to naprawić?

+3

Jest w tym dwa elementy - INSERT i SELECT. Sprawdź, który to jest, po prostu uruchom SELECT. –

+0

Ile pamięci ma serwer? Może się zdarzyć, że zestaw roboczy przekroczy pamięć stopniowo w czasie. – usr

+0

@usr Serwer ma 64GB pamięci RAM, 55 GB adresowane do serwera SQL. Cała dostępna pamięć używana przez MS SQL. Typ dysków - myślę, że HDD. Ale konfiguracja serwera nie zmieniła się z czasem - więc nie mogę zrozumieć tego spadku wydajności. – Ph0en1x

Odpowiedz

5

Jedna z teorii głosi, że pierwszy 50-gigabajtowy zbiór danych wypełnił pamięć dostępną do buforowania. Po obcięciu stołu pamięć podręczna jest teraz pusta. To przemienne zachowanie sprawia, że ​​efektywne korzystanie z pamięci podręcznej jest trudne i powoduje znaczną liczbę pomyłek w pamięci podręcznej/zwiększony czas IO.

Rozważmy następującą sekwencję zdarzeń:

  1. załadować swój początkowy zestaw danych do WriteDb. Podczas operacji ładowania strony w WriteDb są buforowane. Jest bardzo mało rywalizacji o pamięć, ponieważ istnieje tylko jedna kopia zbioru danych i wystarczająca pamięć.
  2. Początkowo wypełniasz ReadDb. Strony wymagane do wypełnienia ReadDb (dane w WriteDb) są już w dużej mierze buforowane. Mniejsza liczba odczytów jest wymagana z dysku, a twój czas IO może być poświęcony na pisanie wstawionych danych do ReadDb. (To jest twój pierwszy szybki bieg.)
  3. Załadujesz drugi zestaw danych do WriteDb. Podczas operacji ładowania nie ma wystarczającej ilości pamięci do buforowania zarówno istniejących danych w ReadDb, jak i nowych danych zapisywanych w WriteDb. Ta rywalizacja o pamięć prowadzi do mniejszej liczby stron pamięci podręcznej WriteDb.
  4. Obciąłeś ReadDb. Powoduje to unieważnienie znacznej części pamięci podręcznej (tj. 50 GB danych ReadDb, które zostały zbuforowane).
  5. Następnie należy spróbować drugiego obciążenia ReadDb. Tutaj masz bardzo mało buforowanej pamięci podręcznej, więc twój czas IO jest podzielony na czytanie stron WriteDb (twoje zapytanie) i pisanie stron ReadDb (twoja wstawka). (To jest twój powolny drugi bieg).

Można przetestować tę teorię, porównując współczynnik chybienia pamięci podręcznej SQL Server podczas pierwszej i drugiej operacji ładowania.

Kilka sposobów na poprawę wydajności może być:

  • użytkowania tablic osobnym dysku dla ReadDb/WriteDb zwiększyć wydajność równolegle IO.
  • Zwiększenie dostępnej pamięci podręcznej (ilość pamięci serwera) w celu dostosowania łącznego rozmiaru ReadDb + WriteDb i zminimalizowania chybienia pamięci podręcznej.
  • Zminimalizuj wpływ każdej operacji ładowania na istniejące strony z pamięci podręcznej, używając instrukcji MERGE zamiast wysyłać/ładować 50 GB danych naraz.