2010-04-12 15 views
8

Testuję szybkość wstawiania wielu wierszy za pomocą pojedynczej instrukcji INSERT.Wiele wierszy z jednym INSERT w SQLServer 2008

Na przykład: WKŁADKA DO [MojaTabela] Wartości (5 ", psa), (6 'kot'), (3„rybiego)

to bardzo szybko, dopóki nie przekroczy 50 rzędach jedno zdanie, potem prędkość znacznie spada.

Wstawienie 10000 rzędów z partiami po 50 sekund zajmuje 0,9 sekundy. Wstawienie 10000 wierszy z partiami 51 zajmuje 5,7 sekundy.

Moje pytanie składa się z dwóch części:

  1. dlaczego jest taki trudny spadek wydajności przy 50?
  2. Czy mogę polegać na tym zachowaniu i zakodować moją aplikację, aby nigdy nie wysyłać partii większych niż 50?

Moje testy zostały wykonane w języku C++ i ADO.

Edycja: Wygląda na to, że punktem odsuwania nie jest 50 wierszy, ale 1000 kolumn. Otrzymuję podobne wyniki w przypadku 50 wierszy z 20 kolumn lub 100 wierszy z 10 kolumn.

+0

Mam wrażenie, że jest gorzej z powodu analizowania danych wejściowych. – Andrey

+2

Pełne i całkowite zgadywanie: mniej niż 50 wierszy jest buforowanych w pamięci RAM przez SQL Server, ale większe wstawki są uważane za bardziej "ważne" i są natychmiast zapisywane na dysku? Szczerze mówiąc nie jestem pewien (stąd komentarz zamiast odpowiedzi) –

Odpowiedz

0

Czy porównałeś również podejście pokazane tutaj "zjednoczenie wszystkich"? http://blog.sqlauthority.com/2007/06/08/sql-server-insert-multiple-records-using-one-insert-statement-use-of-union-all/

Podejrzewam, że istnieje wewnętrzna pamięć podręczna/indeks, który jest używany do 50 wierszy (jest to niezła okrągła liczba dziesiętna). Po 50 wierszach powraca do mniej wydajnego algorytmu wstawiania ogólnego, który może obsłużyć dowolne ilości danych wejściowych bez nadmiernej pamięci.

+0

Właśnie wypróbowałem podejście UNION ALL. Jest również dość powolny. Około 7 sekund dla 10000 wierszy. – Todd

0

spowolnienie jest prawdopodobnie parsowaniem wartości ciągu znaków: VALUES (5, 'dog'), (6, 'cat'), (3, 'fish), a nie problemem WSTAW.

spróbować czegoś takiego, który będzie wstawić jeden wiersz dla każdego wiersza zwracanego przez zapytanie:

INSERT INTO YourTable1 
    (col1, col2) 
    SELECT 
     Value1, Value2 
     FROM YourTable2 
     WHERE ...--rows will be more than 50 

i zobaczyć, co się dzieje

0

Jeśli używasz SQL Server 2008, można użyć wartości stołowego parametry i po prostu wykonaj jedną instrukcję wstawiania.

Osobiście nigdy nie widziałem spowolnienia przy 50 wstawkach, nawet przy regularnych partiach. Niezależnie od tego, przenieśliśmy się do parametrów wartości tabeli, które miały dla nas znaczny wzrost prędkości.

+0

Próbowałem tego i jako początkujący SQL, nie jestem pewien, czy robię to w najbardziej optymalny sposób. Jednak moje testy pokazują od 6 sekund do 30 sekund na 10000 wierszy, w zależności od wielkości partii. Nic w pobliżu instrukcji INSERT z wieloma wierszami. – Todd

+0

To bardzo dziwne. Czy przypisujesz wszystkie pola w tabeli lub czy są one przypisane za pomocą domyślnych wartości kolumny? Jeśli później, mogą one stać się drogie (jak funkcja getdate()) ... – NotMe

+0

Podążyłem za przykładem: http://msdn.microsoft.com/en-us/library/bb510489%28SQL.100%29. aspx Zamiast wstawiania do tabeli tymczasowej z innej tabeli, wstawiam wartości za pomocą wstawki wielorzędowej. Podaję wszystkie wartości, bez wartości domyślnych. – Todd

0

losowe myśli:

  • jest to całkowicie zgodne podczas uruchamiania wielokrotnie?
  • Czy sprawdzasz duplikaty w 1. 10k wierszy dla drugiej wstawki 10k?
  • czy najpierw wypróbowałeś partię o wielkości 51?
  • czy opróżniłeś tabelę między testami?
+0

Tak, jest bardzo spójny. I opróżniam stół pomiędzy każdym testem. – Todd

+0

@Todd: interesujące. Dobre pytanie. I nie mam żadnych dalszych pomysłów :-) – gbn

2

Może to być również związane z rozmiarem rzędu. Tabela, której używasz jako przykładu, wydaje się mieć tylko 2 kolumny. Co jeśli ma 25 kolumn? Czy wydajność spada również w 50 rzędach?

+0

Interesujące. Powyższa tabela była tylko przykładem, moja rzeczywista tabela zawiera 20 kolumn. Skróciłem do 10 i spróbowałem ponownie. Teraz otrzymuję odcięcie przy 100. Partie 100 zabierają około 0,6 sekundy. Partie w liczbie 101 zajmują około 3,25 sekundy. Wygląda na to, że limit nie wynosi 50 wierszy, ale 1000 pojedynczych zaktualizowanych pól? – Todd

+0

Wygląda na to, że odcięcie jest bardziej podobne do wszystkich danych w pamięci. Jeśli tabela jest mała, być może możesz zmieścić 100 wierszy w "bloku", bez względu na blok. Jednak duże tabele z wieloma kolumnami lub z kilkoma dużymi kolumnami (np. VARCHAR (1200)) ograniczałyby liczbę wierszy, które można dopasować do bloku. – MJB

0

W przypadku wkładek o dużej pojemności i wysokiej częstotliwości należy rozważyć użycie Bulk Inserts w celu załadowania danych. To nie jest najprostsza rzecz, którą może wdrożyć świat, a przynosi ze sobą nowe wyzwania, ale może być znacznie szybsze niż wykonanie INSERT.