Catatan menghilang dalam loop transaksi mssql PDO

Saya memiliki kode berikut (kurang lebih) untuk mengimpor 500.000 hingga 4.000.000 baris:

$sSql = "Insert into table (a,b,c) VALUES(?,?,?)"
$oSQLStmnt = $pdo->prepare($sSql);
$oSQLStmnt->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);
if (!$oSQLStmnt) {
    echo $pdo->errorInfo(); // Handle errors
}
$pdo->beginTransaction();
$iLineCounter = 1;
while (($sLine = fgets ($oCSV, 8000)) !== FALSE) {
      $aLine = explode('|', $sLine); //Fgetscsv did not work properly 
       if ($iLineCounter % 100 == 0) {
            lo("Inserting row " . $iLineCounter);
            $pdo->commit();
            sleep(0.15);
            $pdo->beginTransaction();
       }
       try {
            $oSQLStmnt->execute($aLine);
            $iSuccesulInserts++;
       }
       catch (exception $e) {
            print_r($e);
            $iFailedInserts++;
       }

       $iLineCounter++;
}
$pdo->commit();

Seperti yang Anda lihat, saya melakukan komit setiap 100 baris, dan saya bahkan menambahkan beberapa sleep. Saya biasa menjalankan komit hanya sekali setiap 25.000 baris, dan saya tidak menggunakan mode tidur apa pun. Namun, pada satu titik, saya menemukan bahwa saya kehilangan catatan. Saya mulai bermain-main dengan pengaturan ini (tidur dan jumlah baris). Dengan cara ini saya mengurangi jumlah catatan yang hilang dari 50.000 menjadi sekitar 100. Namun saya masih kehilangan catatan! Kemana mereka pergi? Saya tahu SQL-nya baik-baik saja, karena saya langsung menerima kesalahan ketika ada yang salah di sana.

Saya pikir saya bisa menumpuk banyak sisipan selama transaksi? Mungkinkah menelepon BeginTransaction menjadi masalah?

PEMBARUAN:

Hadiahnya berakhir dan saya harus menghadiahkannya. Terima kasih atas jawaban Anda. Atau sebenarnya tip, karena tidak ada di antara Anda yang menjawab pertanyaan saya. Saya tidak meminta solusi, meskipun saran Anda sangat kami hargai. Jawaban yang diberikan bounty untuk menerimanya karena paling mendekati jawaban pertanyaan saya. Sayangnya itu tidak berhasil.

Untuk saat ini saya menggunakan impor massal CSV, itu berfungsi dengan baik, tetapi jika ada yang punya tips lain untuk memperbaiki masalah ini, beri tahu saya. Karena saya lebih suka menggunakan metode asli saya.


person Derk Arts    schedule 02.07.2012    source sumber
comment
Menjalankan kode tanpa mulaiTransaksi dan menumpuk semua kueri penyisipan dalam satu transaksi mengakibatkan hilangnya sekitar 40.000 catatan...   -  person Derk Arts    schedule 02.07.2012
comment
Jika saya mengulangi loop ini tanpa transaksi, itu berfungsi dengan baik. Tidak ada catatan yang hilang...   -  person Derk Arts    schedule 02.07.2012
comment
Masalahnya bukan disebabkan oleh PDO. Itu sudah pasti.   -  person Derk Arts    schedule 02.07.2012
comment
Saya akan mencoba ini msdn.microsoft.com/en-us/library/ms188365.aspx karena ada banyak data di sana   -  person allen213    schedule 02.07.2012
comment
Maksud Anda mengimpor file CSV langsung di SQL? Itu berarti saya harus membaca file CSV, membersihkannya, menulisnya kembali ke CSV lain, dan memasukkannya ke dalam DB. Saya bisa melakukan itu, tetapi rasanya tidak efisien.   -  person Derk Arts    schedule 02.07.2012
comment
Apakah Anda yakin parser CSV buatan Anda tidak bermasalah? Jika Anda menyederhanakan masalah dengan memasukkan array (a$i, b$i, c$i) untuk setiap $i di range(0, 50000) dan menghapus semua kode yang bermasalah (sleeps, try .. catch, dan komitmen menengah), apakah Anda masih dapat mereproduksi masalah tersebut ? Jika ya, bisakah Anda menautkan ke lengkap contoh skrip?   -  person phihag    schedule 04.07.2012
comment
Kemungkinan pengecualian dari $pdo->commit(); dan $pdo->beginTransaction(); tidak tertangkap dengan kode tersebut, jika saya membacanya dengan benar.   -  person vyegorov    schedule 04.07.2012
comment
Phi: Seperti yang dinyatakan, ketika saya meninggalkan transaksi, semuanya lambat tapi baik-baik saja, tidak ada catatan yang hilang, jadi tidak ada masalah dengan parser CSV saya. VYE: Pengecualian apa? Saya pikir pengecualian tersebut akan muncul saat saya menjalankan kueri. Selain itu, ketika saya memperlambat segalanya, saya kehilangan lebih sedikit catatan, jadi kesalahan yang tidak tertangkap dalam SQL bukanlah masalahnya.   -  person Derk Arts    schedule 04.07.2012
comment
Skrip di $sSql tidak memiliki kata kunci VALUES. Apakah kata itu juga hilang dari skrip di kode kerja Anda?   -  person Andriy M    schedule 05.07.2012
comment
apakah commit dan starttansactioan selalu menghasilkan nilai true? ¿catatan yang hilang bersifat korelatif?   -  person    schedule 07.07.2012


Jawaban (4)


Sudahkah Anda mempertimbangkan untuk menggunakan Sprocs daripada menyisipkan pernyataan? menulis sejumlah catatan secara berurutan - satu per satu - hanya membuang-buang waktu / tenaga.. hanya saja tidak secepat yang seharusnya.

Apakah Anda yakin tidak dapat menggunakan BULK INSERT atau XML untuk menyisipkan beberapa baris sekaligus?

person Aaron Kempf    schedule 05.07.2012
comment
Itulah yang saya lakukan saat ini sebagai solusinya. Tapi menurutku sungguh menyedihkan jika catatan-catatan itu hilang tanpa pemberitahuan... - person Derk Arts; 05.07.2012

Saya punya masalah ini sebelumnya. Bagi saya, saya harus melakukan "SET NOCOUNT ON" sebelum INSERTS karena SQL Server mencoba mengembalikan saya "Satu baris ditambahkan" untuk setiap INSERT dan antrian pesannya penuh dan berhenti memasukkan data, tanpa mengembalikan kesalahan apa pun!

Jadi Anda harus mencoba melakukan "SET NOCOUNT ON" sebelum INSERTS. Saya yakin ini akan memperbaiki masalah Anda.

person Danielle Paquette-Harvey    schedule 04.07.2012
comment
Kedengarannya sangat masuk akal! Akan mencobanya hari ini! - person Derk Arts; 05.07.2012
comment
Sebelum setiap pernyataan penyisipan atau hanya sekali? - person Derk Arts; 05.07.2012
comment
Sayangnya tidak menyelesaikannya. '14:57:10[119] | HASIL UNTUK tabel: Total baris: 466792Berhasil: 466789 Gagal: 2' -› select count(*) from table = 441925 - person Derk Arts; 05.07.2012

Anda menggunakan sleep () 0,15 detik untuk menunda eksekusi, namun pertanyaannya: Apa yang terjadi jika INSERT memakan waktu lebih dari 0,15 detik? Skrip untuk dijalankan kembali dan tabel mungkin diblokir karena penerapan sebelumnya.

Kemudian coba pendekatan beberapa INSERT dalam sekali jalan di database. Cobalah sesuatu seperti ini:

INSERT INTO example (example_id, name, value, other_value)VALUES
(100, 'Name 1', 'Value 1', 'Other 1'), (101, 'Name 2', 'Value 2', 'Other 2'),
(102, 'Name 3', 'Value 3', 'Other 3'), (103, 'Name 4', 'Value 4', 'Other 4');

Untuk mencapai hal ini, lakukan:

$sql = ' INSERT INTO example (example_id, name, value, other_value)VALUES';
while (($sLine = fgets ($oCSV, 8000)) !== FALSE) {
    // generate VALUES to INSERT in a $sql .= '(..., ..., ...),'
}

Lalu lari!

person Maykonn    schedule 06.07.2012

@Saratis,

Sudahkah Anda mempertimbangkan untuk membuat sproc sederhana yang melakukan tindakan yang diinginkan menggunakan MERGE? Penggabungan akan memakan banyak overhead, namun, saya selalu tahu bahwa ini adalah cara yang sangat andal untuk menyinkronkan catatan dari sumber data 'master' ke sumber data dependen.

Saya menganut filosofi bahwa Basis Data harus mengontrol BAGAIMANA data digunakan, dan kode harus mengontrol KAPAN basis data melakukan apa yang dilakukannya. Apa yang saya lebih suka lakukan adalah menyimpan apa pun yang menyentuh data dalam proses tersimpan, dan memanggil proses tersimpan dengan kode ketika kondisi/peristiwa tertentu terjadi. Namun, situasi Anda mungkin cukup unik sehingga hal ini bukanlah praktik terbaik.

Cuplikan kode di bawah ini berasal dari Microsoft sebagai contoh cara melakukan penggabungan:

MERGE Production.UnitMeasure AS target
USING (SELECT @UnitMeasureCode, @Name) AS source (UnitMeasureCode, Name)
ON (target.UnitMeasureCode = source.UnitMeasureCode)
WHEN MATCHED THEN 
    UPDATE SET Name = source.Name
WHEN NOT MATCHED THEN   
    INSERT (UnitMeasureCode, Name)
    VALUES (source.UnitMeasureCode, source.Name)
    OUTPUT deleted.*, $action, inserted.* INTO #MyTempTable;

Berikut ini tautan ke seluruh artikel, yang mencakup beberapa skenario berbeda: http://technet.microsoft.com/en-us/library/bb510625.aspx

Sekarang, untuk memasukkan informasi ke dalam SQL Server dari CSV, tautan berikut menjelaskan bagaimana hal itu dapat dicapai dengan menggunakan jalur file sebagai bagian dari klausa FROM, dan menentukan pembatas dalam klausa WITH.

Ini mencakup BULK INSERT juga, jika itu mungkin yang terbaik untuk Anda, namun, saya lebih memilih MERGE karena menangani INSERT untuk catatan baru dan UPDATES catatan yang ada. http://sqlserverpedia.com/blog/sql-server-bloggers/so-you-want-to-read-csv-files-huh/

FYI, BULK INSERT hanya berfungsi jika file berada di disk yang sama dengan contoh SQL Server. Dapat dimengerti bahwa perusahaan saya tidak akan memberi saya akses ke drive lokal SQL Server, jadi saya harus mengujinya di rumah malam ini untuk memberi Anda contoh kerja untuk digunakan.

person EastOfJupiter    schedule 05.07.2012
comment
Ini bagus, tapi menurut saya ini tidak berlaku untuk impor file CSV, atau apakah saya salah? - person Derk Arts; 10.07.2012
comment
Saya minta maaf, saya tidak melihat di postingan asli Anda bahwa Anda mengimpor dari CSV. Tautan ini mungkin menawarkan solusi. sqlserverpedia.com/blog /sql-server-bloggers/ Pilih CSV menjadi Common Table Expression lalu lakukan Penggabungan. Saya akan memperbarui jawaban saya untuk menyertakan tautan ini juga. - person EastOfJupiter; 10.07.2012