Jak uruchomić duży skrypt z wieloma wstawkami bez wyczerpania pamięci?

28

Pytanie:

Mam skrypt z około 45 tysiącami wstawek z wybranych instrukcji. Podczas próby uruchomienia pojawia się komunikat o błędzie informujący, że zabrakło mi pamięci. Jak mogę uruchomić ten skrypt?

Kontekst:

  1. Dodano nowe pola danych, aby aplikacja działała przyjemnie z inną aplikacją, z której korzysta klient.
  2. Dostałem arkusz kalkulacyjny danych od klienta pełnego danych, który zamapował bieżące elementy danych na wartości dla tych nowych pól.
  3. Konwertowany arkusz kalkulacyjny do wstawiania instrukcji.
  4. Jeśli uruchomię tylko niektóre instrukcje, działa, ale nie działa cały skrypt.
  5. Nie. Nie ma literówek.

Jeśli istnieje inny sposób, powinienem ładować te dane, możesz mnie ukarać i dać mi znać.

spaghetticowboy
źródło
Podobne pytanie na temat SO: ( stackoverflow.com/questions/222442/... ) Nie jestem pewien, czy odpowiedź pomoże
Jumpdart

Odpowiedzi:

17

Maksymalny rozmiar partii dla SQL Server 2005 wynosi 65 536 * Rozmiar pakietu sieciowego (NPS), gdzie NPS to zwykle 4KB. To działa do 256 MB. Oznaczałoby to, że każda instrukcja wstawiania miałaby średnio 5,8 KB. To nie wydaje się właściwe, ale może są tam obce przestrzenie lub coś niezwykłego.

Moją pierwszą sugestią byłoby umieszczenie instrukcji „GO” po każdej instrukcji INSERT. Spowoduje to rozbicie pojedynczej partii 45 000 instrukcji INSERT na 45 000 oddzielnych partii. Powinno to być łatwiejsze do strawienia. Bądź ostrożny, jeśli jedna z tych wkładek zawiedzie, możesz mieć trudności ze znalezieniem winowajcy. Możesz się zabezpieczyć przed transakcją. Możesz szybko dodać te instrukcje, jeśli twój edytor ma dobre wyszukiwanie i zamianę (co pozwoli ci wyszukiwać i zamieniać znaki powrotu, takie jak \ r \ n) lub funkcję makr.

Drugą sugestią jest użycie Kreatora do importowania danych bezpośrednio z Excela. Kreator buduje dla ciebie mały pakiet SSIS, a następnie uruchamia go. Nie będzie miał tego problemu.

cieśnina Darina
źródło
2
GOPo każdym stwierdzeniem? Myślę, że jeśli generujesz je przy użyciu innego skryptu, to jest OK. W przeciwnym razie po prostu wstawiałbym jeden po każdych 1000 INSERTs. Jeśli chodzi o tworzenie transakcji atomowych i minimalizowanie wielkości transakcji, dlaczego nie załadować wszystkich wierszy do tabeli tymczasowej lub zmiennej tabeli, a następnie załadować je jednym strzałem stamtąd do tabeli docelowej?
Nick Chammas,
1000 jest tak samo dobre jak 1, ale trudniejsze do policzenia. Szczerze mówiąc, może uciec mu tylko jedno oświadczenie GO, w połowie drogi, blisko oświadczenia 21.500. Podoba mi się poprawka GO, ponieważ nie wymaga skomplikowanej edycji bieżącego skryptu ani liczenia instrukcji INSERT (które mogą nie być mapowane bezpośrednio na numery wierszy).
cieśnina Darina
2
Z pewnością nawet złe przybliżenie 1000 instrukcji jest wystarczające. :)
Nick Chammas,
1
Dodanie GO było szybką i łatwą naprawą. Skrypt 25 MB działa w nieco mniej niż 9 minut bez żadnych problemów. Chciałem mieć go jako skrypt, aby zachować go w ramach naszego standardowego procesu wdrażania łatki na wypadek, gdy zniknie.
spaghetticowboy
14

BULK INSERTlub bcpwydają się bardziej odpowiednie opcje niż 45 000 instrukcji wstawiania.

Jeśli chcesz trzymać się instrukcji wstawiania, rozważę kilka opcji:

Odp .: Użyj transakcji i zawiń partie po 100 lub 500 lub 1000 wyciągów w każdym, aby zminimalizować wpływ na dziennik i partię. na przykład

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

B: Zamiast pojedynczych instrukcji wstawiania używaj jednocześnie UNION ALL100 lub 500 instrukcji, np

INSERT dbo.table(a, ...)
SELECT 1, ...
UNION ALL SELECT 2, ...
...
UNION ALL SELECT 500, ...
GO

INSERT dbo.table(a, ...)
SELECT 501, ...
UNION ALL SELECT 502, ...
...
UNION ALL SELECT 1000, ...
GO

Zostawiłem błąd dotyczący zwięzłości, ale chodzi o to, że nigdy nie próbowałbym wysłać pojedynczej partii 45 000 pojedynczych instrukcji do SQL Server.

Aaron Bertrand
źródło
1
Szkoda, że ​​OP nie może używać konstruktorów o wartości tabeli , funkcja 2008+. Nadal będzie musiał grupować wkładki w grupy po 1000 wierszy, co stanowi maksimum, które można pogrupować razem z TVC.
Nick Chammas,
To była moja pierwsza sugestia, dopóki nie zobaczyłem tagu wersji.
Aaron Bertrand
2
@NickChammas - Wydajność tych spada nieliniowo wraz z liczbą klauzul wartości BTW . Poddałem connect element z Repro wstawiania 1000 wiersze z 10 VARCHAR(800)kolumn na 2008 z kompilacji czasie 12,5 minuty na moim 2008 przykład dev jak to robi wiele niepotrzebnych wartości pracy porównując zamiast po prostu wsiąść z włożeniem (sprawuje się dużo szybciej po sparametryzowaniu i bez wartości do obejrzenia). Chociaż znacznie poprawiony w 2012 roku, nieliniowy wzór nadal istnieje i powinien zostać naprawiony w wersji później.
Martin Smith
9

Nie jestem pewien, dlaczego występuje błąd braku pamięci, ale istnieje łatwiejsze podejście.

Jeśli możesz wyeksportować dane z arkusza kalkulacyjnego do formatu rozdzielanego (np. Csv), możesz użyć kreatora importu danych w SSMS, aby wstawić dane:

Zadanie importowania danych SSMS.

datagod
źródło
to jest pomocne, ale nie mam dostępu do baz danych klientów. Muszę przygotowywać łatki i ładowanie danych w skryptach
spaghetticowboy,
0

Używając wielu SqlBulkCopy, utwórz tabelę tymczasową. Wstaw nowe dane do tabeli tymczasowej, a następnie scal dane z tabeli tymczasowej z istniejącą. Przykład z wykorzystaniem metody C # SqlBulkCopy.WriteToServer (DataTable) . Mam nadzieję, że to pomoże

Hung Vu
źródło
0

Tak, moglibyśmy to zrobić, próbowałem z podejściem BCP (Bulk Copy Program), aby uniknąć problemu z OutOfMemory .

Uwaga : Wypróbowano na SQL Server 2014.

W BCP najpierw musimy wyeksportować dane źródłowej bazy danych do pliku bcp (w folderze katalogu lokalnego), a następnie zaimportować ten plik bcp do docelowej bazy danych.

wprowadź opis zdjęcia tutaj

Poniżej znajdują się kroki chodzenia po torcie:

Uwaga:

a) Upewnij się, że pusta tabela jest obecna w docelowej bazie danych

b) Upewnij się, że folder Temp znajduje się na dysku C.

  1. Utwórz plik nietoperza o nazwie Export_Data.bat za pomocą polecenia pokazanego poniżej:

    bcp.exe [Source_DataBase_Name].[dbo].[TableName] OUT "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 

    pauza

  2. Uruchom ten plik nietoperza, w wyniku czego plik bcp zostanie wygenerowany w folderze Temp

  3. Następnie utwórz kolejny plik nietoperza o nazwie Import_Data.bat za pomocą następującego polecenia:

    bcp.exe [Destination_DataBase_Name].[dbo].[TableName] IN "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 

    Pauza

I zaczynamy!

Kms
źródło
Wystąpił błąd „Prawidłowa nazwa tabeli jest wymagana dla opcji wejścia, wyjścia lub formatowania”. podczas próby eksportu danych.
Sen Jacob
1
Czy możesz wkleić wypróbowane polecenie z całą wartością atrybutu. Wykonaj następujący przykład: bcp.exe ExportDB.dbo.AddressCountry OUT "C: \ Temp \ AddressCountry.bcp" -S "IN-L20054" -U "sa" -P „sa” -n -q W tym [ExportDB -> Source DB, AddressCountry-> Tabela obecna w Source DB, IN-L20054 -> Nazwa maszyny, „sa” to nazwa użytkownika / pwd DB]
Kms
Nie mam tego teraz. Skończyło się na użyciu funkcji importowania danych w SSMS. Następnie podłączono docelową DB (v14.0) do źródłowej DB (v.15.0) za pomocą połączenia MS OLE DB i dość szybko zaimportowano wiele milionów wierszy danych. Dzięki!
Sen Jacob