Belleği yetersiz olmadan birçok ek içeren büyük bir komut dosyasını nasıl çalıştırabilirim?


28

Soru:

Seçilmiş ifadelerden yaklaşık 45 bin alıntı içeren bir senaryom var. Denemeye çalıştığımda, hafızamın tükendiğini belirten bir hata mesajı alıyorum. Bu betiğin çalışmasını nasıl sağlayabilirim?

Bağlam:

  1. Bir uygulamanın, müşterinin kullandığı başka bir uygulama ile iyi çalışmasını sağlamak için bazı yeni veri alanları eklendi.
  2. İstemciden, mevcut veri öğelerini bu yeni alanların değerleriyle eşleştiren veri dolu bir veri tablosu aldım.
  3. İfade eklemek için elektronik tablo dönüştürüldü.
  4. Eğer sadece bazı ifadeleri çalıştırırsam, işe yarıyor ama tüm script çalışmıyor.
  5. Hayır. Yazım hatası yok.

Farklı bir yol varsa, bu verileri yüklemeliyim, beni şaşırtmaktan ve bana bildirmekten çekinmeyin.


SO üzerinde benzer bir soru: ( stackoverflow.com/questions/222442/… ) Cevabın
işe yarayıp yaramadığından

Yanıtlar:


17

SQL Server 2005 için maksimum parti boyutu NPS'nin genellikle 4KB olduğu 65.536 * Ağ Paket Boyutu'dur (NPS). 256 MB'a kadar çalışır. Bu, insert ifadelerinizin her birinin ortalama 5,8 KB olacağı anlamına gelir. Bu doğru gözükmüyor, ama belki de fazladan boşluklar var veya içinde olağandışı bir şey var.

İlk önerim, her INSERT ifadesinden sonra bir "GO" ifadesi koymak olacak. Bu, tek bir 45.000 INSERT ifadesi kümenizi 45.000 ayrı gruba böler. Bu sindirimi daha kolay olmalı. Dikkatli olun, eğer bu eklerden biri arızalanırsa, suçluyu bulmakta zorlanabilirsiniz. Kendinizi bir işlemle korumak isteyebilirsiniz. Editörünüzün iyi bir ara ve değiştir özelliği varsa (\ r \ n gibi karakterleri aramanıza ve değiştirmenize izin verecek) veya bir makro özelliğine sahipseniz bu ifadeleri hızlı bir şekilde ekleyebilirsiniz.

İkinci öneri, verileri doğrudan Excel'den içe aktarmak için bir Sihirbaz kullanmaktır. Sihirbaz, sahne arkasında sizin için küçük bir SSIS paketi oluşturur ve sonra bunu çalıştırır. Bu problemi yaşamayacak.


2
Bir GOsonraki her açıklamada? Sanırım onları başka bir senaryo kullanarak oluşturuyorsanız, sorun değil. Aksi takdirde, her 1000 INSERTsaniyeden sonra bir tane koyardım. İşlemin atomik hale getirilmesi ve işlemin büyüklüğünün en aza indirilmesi ile ilgili olarak, neden tüm satırları bir geçici tabloya veya tablo değişkenine yüklemiyor ve sonra bunları tek bir atışla oradan hedef tabloya yüklüyorsunuz?
Nick Chammas

1000, 1 kadar iyidir, ancak sayılması zordur. Dürüst olmak gerekirse, 21.500 deyimine yakın bir noktada, sadece bir GO bildirimi ile kaçabilir. GO düzeltmesini seviyorum, çünkü mevcut betiğin karmaşık bir şekilde düzenlenmesi veya INSERT deyimlerinin sayılması (doğrudan satır numaralarıyla eşleşmeyebilir) gerektirmiyor.
darin boğazı,

2
Elbette, 1000 ifadenin hatalı bir şekilde tahmin edilmesi bile yeterince iyidir. :)
Nick Chammas,

1
GO'ları eklemek hızlı ve kolay bir çözümdü .. 25mb komut dosyası 9 dakikadan az bir sürede sorunsuz çalışıyor. Dışarı çıktığı zaman için standart yama dağıtım sürecimizde kalmasını sağlayacak bir komut dosyası olmasını istedi.
spaghetticowboy

14

BULK INSERTveya bcp45.000 insert ifadesinden daha uygun seçenekler gibi görünüyor.

İnsert ifadelerine bağlı kalmanız gerekirse, birkaç seçeneği göz önünde bulundururum:

Y: Günlük ve küme üzerindeki etkiyi en aza indirmek için işlemleri kullanın ve her birinde 100 veya 500 veya 1000 deyim içeren kümeleri paketleyin. Örneğin

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: Bireysel ekleme ifadeleri yerine UNION ALL, bir kerede 100 veya 500 ifade kullanın , örn.

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

Kesinlik için hata yapma konusunda bir hata yapmadım, ama asıl nokta, SQL Server'a asla tek bir 45.000 ayrı ifade demeti göndermeye çalışmam.


1
Çok kötü bir şekilde OP, 2008+ özellikli tablo-değer yapıcılarını kullanamaz. Ekleri 1000 satırlık gruplar halinde toplaması gerekiyordu; bu da bir TVC ile birlikte gruplayabileceğiniz maksimum sayı.
Nick Chammas

Sürüm etiketini görene kadar bu benim ilk önerim olacaktı.
Aaron Bertrand

2
@NickChammas - Buların BTW değer cümlelerinin sayısı ile doğrusal olmayan bir şekilde düşmesi . 2008 dev örneğinde 12.5 dakikalık bir derleme süresine sahip 2008 sütununda 1000 sütun ekleyen bir repro ile bir bağlantı öğesi gönderdim . parametreleştirildiğinde daha hızlı ve bakılacak değer yok). 2012 yılında çok gelişmiş olmasına rağmen, doğrusal olmayan model hala var ve sonraki versiyonda düzeltilmelidir. VARCHAR(800)
Martin Smith

9

Neden bellek yetersizliği hatası aldığınızdan emin değilim, ancak daha kolay bir yaklaşım var.

Verileri e-tablodan ayrılmış bir formata (örn. Csv) verebilirsiniz, verileri eklemek için SSMS'deki veri alma sihirbazını kullanabilirsiniz:

SSMS veri alma görevi.


Bu yararlı ama istemciler veritabanlarına erişimim yok. Kodlarda yamalar ve veri yükleri hazırlamalıyım
spagetticowboy


0

Evet bunu yapabiliriz, bir OutOfMemory sorununu önlemek için BCP (Toplu Kopyalama Programı) yaklaşımını denedim .

Not : SQL Server 2014'te denendi.

BCP'de, önce Kaynak veritabanı verilerini bcp dosyasına (yerel dizin klasöründe) vermemiz ve sonra bu bcp dosyasını hedef veritabanına içe aktarmamız gerekir .

görüntü tanımını buraya girin

Aşağıda kek yürüyüşü basamakları yer almaktadır:

Not:

a) Hedef veritabanında boş tablonun bulunduğundan emin olun

b) emin olun Temp klasörünü mevcuttur C sürücüsüne

  1. Aşağıdaki komutu kullanarak Export_Data.bat adlı bir yarasa dosyası oluşturun :

    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 

    Duraklat

  2. Bu yarasa dosyasını çalıştırın, bunun sonucunda Temp klasöründe bir bcp dosyası oluşturulur.

  3. Ardından , aşağıdaki komutla Import_Data.bat adlı başka bir yarasa dosyası oluşturun :

    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 

    Duraklat

Ve işte başlıyoruz!


Hata al "Geçerli bir tablo adı giriş, çıkış veya format seçenekleri için gerekli." veri dışa aktarılmaya çalışıldığında.
Sen Jacob,

1
Tüm nitelik değeriyle denediğiniz komutu yapıştırır mısınız? Lütfen aşağıdaki örneği izleyin: bcp.exe ExportDB.dbo.AddressCountry OUT "C: \ Temp \ AddressCountry.bcp" -S "IN-L20054" -U "sa" -P "sa" -n -q [ExportDB -> Kaynak DB, Adres Numarası) -> Kaynak DB'de Bulunan Tablo, IN-L20054 -> Makine Adı, "sa", DB'nin kullanıcı adı / pwd'sidir]
Kms

Şimdi sahip değilim. SSMS’de veri alma özelliğini kullanarak sona erdi. Daha sonra MS OLE DB bağlantısını kullanarak hedef DB'yi (v14.0) DB'ye (v.15.0) bağladı ve multi-milyon veri satırını almak oldukça hızlıydı. Teşekkürler!
Sen Jacob
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.