2012-07-02 29 views
6

Tôi đã đoạn mã sau (nhiều hơn hoặc ít hơn) để nhập khẩu bất cứ nơi nào từ 500.000 đến 4.000.000 hàng:ghi biến mất trong vòng PDO giao dịch MSSQL

$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(); 

Như bạn thấy, tôi thực hiện một cam kết mỗi 100 dòng và thậm chí tôi còn ngủ thêm chút nữa. Tôi đã từng chạy cam kết chỉ một lần mỗi 25.000 dòng, và tôi đã không sử dụng bất kỳ giấc ngủ. Tuy nhiên, tại một thời điểm, tôi phát hiện ra tôi đã mất tích hồ sơ. Tôi bắt đầu chơi với các cài đặt này (ngủ và số hàng). Bằng cách này tôi đã giảm số lượng bản ghi còn thiếu từ 50.000 xuống còn khoảng 100. Nhưng tôi vẫn thiếu hồ sơ! Họ đang đi đâu vậy? Tôi biết SQL là ok, bởi vì tôi ngay lập tức nhận được lỗi khi somethings sai ở đó.

Tôi nghĩ tôi có thể xếp chồng nhiều lần chèn trong khi giao dịch? Có thể gọi beginTransaction là một vấn đề?

UPDATE:

Các tiền thưởng đã kết thúc và tôi phải giải nó. Cảm ơn tất cả các câu trả lời của bạn. Hoặc lời khuyên thực sự, vì không ai trong số các bạn thực sự trả lời câu hỏi của tôi. Tôi đã không yêu cầu một workaround, mặc dù bạn đề xuất được nhiều đánh giá cao. Câu trả lời tiền thưởng đã được trao để nhận nó vì nó đến gần nhất để thực sự trả lời câu hỏi của tôi. Không may, nó không hoạt động.

Hiện tại tôi đang sử dụng nhập số lượng lớn CSV, hoạt động tốt, nhưng nếu có ai đó có bất kỳ mẹo nào khác để khắc phục sự cố này, vui lòng cho tôi biết. Khi tôi thích sử dụng phương pháp ban đầu của tôi.

+0

Chạy mã mà không bắt đầuTruy cập và xếp tất cả các truy vấn chèn trong một kết quả giao dịch sẽ mất khoảng 40.000 bản ghi ... –

+0

Nếu tôi lặp lại vòng lặp này mà không có giao dịch, nó hoạt động tốt. Không có hồ sơ nào bị mất ... –

+0

Vấn đề không phải do PDO gây ra. Chắc chắn rồi. –

Trả lời

1

Bạn đã cân nhắc sử dụng Sprocs thay vì chèn câu lệnh? viết BẤT K number số lượng hồ sơ tuần tự - từng lần một - là một sự lãng phí thời gian/năng lượng .. nó chỉ không nhanh như trước.

Bạn có chắc chắn không thể sử dụng BULK INSERT hoặc XML thay vì chèn nhiều hàng cùng một lúc không?

+0

Đó là những gì tôi đang làm ngay bây giờ như là một workaround. Nhưng tôi nghĩ rằng nó chỉ là khủng khiếp mà các hồ sơ đang biến mất mà không cần bất kỳ thông báo nào ... –

+0

Nhập CSV hàng loạt là cách đáng tin cậy duy nhất để thực hiện việc này. –

3

Tôi đã gặp sự cố này trước đây. Đối với tôi, tôi phải thực hiện "SET NOCOUNT ON" trước INSERTS vì SQL Server đang cố trả lại cho tôi "Một hàng đã thêm" cho mỗi INSERT và hàng đợi tin nhắn đầy và nó chỉ dừng việc chèn dữ liệu mà không trả lại bất kỳ lỗi nào!

Vì vậy, bạn chắc chắn nên cố gắng thực hiện "SET NOCOUNT ON" trước INSERTS. Tôi đặt cược nó sẽ sửa chữa vấn đề của bạn.

+0

Nghe có vẻ hoàn toàn hợp lý! Hãy thử ngay hôm nay! –

+0

Trước mỗi câu lệnh chèn hoặc chỉ một lần? –

+0

Không giải quyết được sự cố. '14: 57: 10 [119] | KẾT QUẢ CHO bảng: Tổng số dòng: 466792Thực hiện: 466789 Không thành công: 2 '-> 'chọn đếm (*) từ bảng' = '441925' –

2

@Saratis,

Bạn đã cân nhắc tạo một sproc đơn giản thực hiện hành động mong muốn bằng MERGE chưa? Sáp nhập sẽ tiêu thụ một số chi phí đáng kể, tuy nhiên, tôi đã luôn luôn biết nó là một cách rất đáng tin cậy để đồng bộ hóa các bản ghi từ một nguồn dữ liệu 'chủ' đến một nguồn dữ liệu phụ thuộc.

Tôi là triết lý mà Cơ sở dữ liệu nên kiểm soát dữ liệu CÁCH được sử dụng, và mã nên kiểm soát KHI cơ sở dữ liệu làm những gì nó làm. Những gì tôi thích làm là giữ bất cứ điều gì chạm vào dữ liệu trong một proc được lưu trữ, và gọi procs được lưu trữ với mã khi một số điều kiện/sự kiện xảy ra. Tuy nhiên, tình hình của bạn có thể là duy nhất đủ để đây không phải là một cách thực hành tốt nhất.

Đoạn mã dưới đây xuất phát từ Microsoft như một ví dụ về làm thế nào để thực hiện một hợp nhất:

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; 

Dưới đây là liên kết cho toàn bộ bài viết, trong đó bao gồm một vài kịch bản khác nhau: http://technet.microsoft.com/en-us/library/bb510625.aspx

Bây giờ, để lấy thông tin vào SQL Server từ một CSV, liên kết sau giải thích cách có thể đạt được bằng cách sử dụng đường dẫn tệp như là một phần của mệnh đề FROM và chỉ định dấu phân cách trong mệnh đề WITH.

Nó bao gồm BULK INSERT, nếu điều đó có thể làm việc tốt nhất cho bạn, tuy nhiên, tôi là một phần của MERGE vì nó xử lý cả INSERT cho bản ghi mới và CẬP NHẬT bản ghi hiện có. http://sqlserverpedia.com/blog/sql-server-bloggers/so-you-want-to-read-csv-files-huh/

FYI, BULK INSERT chỉ hoạt động nếu các tệp nằm trên cùng một đĩa với phiên bản SQL Server. Công ty của tôi dễ hiểu sẽ không cấp cho tôi quyền truy cập vào các ổ đĩa cục bộ của SQL Server, vì vậy tôi sẽ phải kiểm tra điều này ở nhà tối nay để giúp bạn làm ví dụ làm việc.

+0

Điều này thật tuyệt, nhưng tôi không nghĩ rằng nó áp dụng cho việc nhập tệp CSV hoặc tôi nhầm? –

+0

Tôi xin lỗi, tôi không thấy được trong bài đăng gốc mà bạn đã nhập từ CSV. Liên kết này có thể cung cấp giải pháp. http://sqlserverpedia.com/blog/sql-server-bloggers/so-you-want-to-read-csv-files-huh/ Chọn CSV thành Biểu thức Bảng chung rồi thực hiện Hợp nhất. Tôi cũng sẽ cập nhật câu trả lời của mình để đưa vào liên kết này. – EastOfJupiter

3

Bạn sử dụng chế độ ngủ() 0,15 giây để trì hoãn việc thực hiện, tuy nhiên, câu hỏi: Điều gì sẽ xảy ra nếu INSERT mất hơn 0,15 giây? Kịch bản lệnh để chạy lại và bảng có thể bị chặn vì cam kết trước đó.

Sau đó thử một cách tiếp cận của nhiều INSERT trong một lần chạy trong cơ sở dữ liệu. Hãy thử một cái gì đó như thế này:

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'); 

Để đạt được điều này, cần làm:

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

Và sau đó chạy!

Các vấn đề liên quan