2010-07-28 20 views
7

Tôi có một câu hỏi đơn giản mà trả 25.026 hàng:MySqlDataReader dừng đọc sau khoảng 4 phút và trả

MySqlCommand cmd = new MySqlCommand("SELECT ID FROM People", DB); 
MySqlDataReader reader = cmd.ExecuteReader(); 

(ID là một int.) Nếu tôi chỉ làm điều này:

int i = 0; 
while (reader.Read()) i++; 

i sẽ bằng 25026. Tuy nhiên, tôi cần thực hiện một số quy trình trên mỗi ID trong vòng lặp của mình; mỗi lần lặp lại kết thúc ở một nơi nào đó trong hàng trăm mili giây.

int i = 0; 
MySqlCommand updater = new MySqlCommand("INSERT INTO OtherTable (...)", anotherConnection); 
updater.Prepare(); 
while (reader.Read()) { 
    int id = reader.getInt32(0); 
    // do stuff, then 
    updater.ExecuteNonQuery(); 
    i++; 
} 

Tuy nhiên, sau khoảng 4:15 xử lý, reader.Read() đơn giản trả về sai. Trong hầu hết các thử nghiệm của tôi chạy, i bằng 14896, nhưng đôi khi nó dừng lại ở 11920. Việc bỏ số DataReader sau khi cùng một số lượng hồ sơ là đáng ngờ và thời gian dừng lại sau một số hàng khác nhau có vẻ xa lạ hơn.

Tại sao reader.Read() trả về false khi chắc chắn có nhiều hàng hơn? Không có ngoại lệ nào bị ném – thậm chí không phải ngoại lệ cơ hội đầu tiên.


Cập nhật: tôi đã đề cập trong câu trả lời của tôi để Shaun's answer rằng tôi đã trở thành tin rằng MySqlDataReader.Read() được nuốt một ngoại lệ, vì vậy tôi đã tải về Connector/Net's source code (bzr branch lp:connectornet/6.2 C:/local/path) và bổ sung dự án để giải pháp của tôi. Chắc chắn, sau 6:15 xử lý, là một ngoại lệ!

Cuộc gọi tới resultSet.NextRow() ném một số MySqlException với thông báo "Đọc từ luồng không thành công". Các InnerException là một SocketException:

{ Message: "An existing connection was forcibly closed by the remote host", 
    ErrorCode: 10054, 
    SocketErrorCode: ConnectionReset } 

10054 có nghĩa là socket TCP đã bị hủy bỏ với một RST thay vì bắt tay bình thường ngắt kết nối (FIN, FIN ACK, ACK), mà nói với tôi điều gì đó screwy đang xảy ra với kết nối mạng.

Trong my.ini, tôi đã quay số interactive_timeoutwait_timeout đến 1814400 (giây) không có kết quả.

Vậy ... tại sao kết nối của tôi bị hỏng sau khi đọc trong 6:15 (375 giây)?

(Ngoài ra, tại sao lại là ngoại lệ này bị nuốt khi tôi sử dụng hệ nhị phân chính thức? Nó trông như nó nên bong bóng lên đến mã ứng dụng của tôi.)

+0

Câu lệnh chèn 14895th trông như thế nào? Ngoài ra, chỉ là một quan sát, nhưng 4:15 là 255s. Có một truy cập một nơi nào đó liên quan đến một trong hai người đọc hoặc chèn trải qua một tràn im lặng? – Tahbaza

+0

@Tahbaza: Chèn không khác gì phần còn lại. Dù sao, vì nó thực hiện trên một 'MySqlConnection' thứ hai, nó sẽ không ảnh hưởng đến cái đầu tiên mà' DataReader' đang bật. Theo thời gian, nó là 4:15 ± 15s; Tôi đã không thực hiện bất kỳ thời gian chính xác nào. Tôi không có bất kỳ quầy nào khác ngoài 'i', vì vậy tôi không nghĩ đó là một sự tràn ngập. – josh3736

+0

Bạn đã kiểm tra xem đó có phải là thời gian chờ thực thi tập lệnh không? – robert

Trả lời

2

Vì tôi chỉ đọc int s, tôi cuối cùng chỉ đọc toàn bộ resultset thành một List<int>, đóng trình đọc và sau đó đã xử lý của tôi. Điều này là tốt cho int s kể từ khi thậm chí một triệu mất < 100 MB RAM, nhưng tôi vẫn thất vọng rằng vấn đề gốc không được giải quyết – nếu tôi đọc nhiều hơn một đơn int mỗi hàng, bộ nhớ sẽ trở thành vấn đề rất lớn với một tập dữ liệu lớn.

1

Cố gắng thiết lập thời gian chờ kết nối lâu hơn.

+0

Tôi không nghĩ đây là vấn đề thời gian chờ - đặc biệt vì không có ngoại lệ nào bị ném. Sự hiểu biết của tôi là 'MySqlConnection.ConnectionTimeout' là khoảng thời gian' MySqlConnection' sẽ đợi khi * thiết lập * một kết nối, không bao lâu nó sẽ giữ cho kết nối mở. 'MySqlCommand.CommandTimeout' là lượng thời gian truy vấn được phép chạy trên máy chủ. Mặc định là không giới hạn. – josh3736

0

Có thể đây là thời gian chờ ở phía máy chủ không?

+0

Tôi nghĩ rằng một thời gian chờ trên máy chủ sẽ tăng một ngoại lệ. Ở mức độ nào, tôi đặt thời gian chờ cao vô cùng trong cấu hình máy chủ của tôi và không thấy thay đổi. – josh3736

0

Thử đặt thời gian chờ trên MySqlCommand chứ không phải MySqlConnection trên cả hai "cmd" và "updater". Điều gì sẽ xảy ra nếu bạn làm: SELECT TOP 100 ID FROM PEOPLE?

+0

Vì vậy, trong khi [yêu cầu tài liệu] (http://dev.mysql.com/doc/refman/5.0/es/connector-net-examples-mysqlcommand.html # connector-net-example-mysqlcommand-commandtimeout) thời gian chờ lệnh mặc định là không giới hạn, sau khi duyệt [source] (http://bazaar.launchpad.net/~mysql-clr-team/connectornet/6.2/annotate/ head% 3A/MySql.Data/Provider/Source/command.cs # L138), có vẻ như mặc định thực sự là 30 giây. Dù bằng cách nào, thời gian chờ không giải thích tại sao 'MySqlDataReader' dừng sau 4 phút. Ngoài ra, thời gian chờ của lệnh ảnh hưởng đến truy vấn * thực thi *, không phải là luồng dữ liệu. – josh3736

0

Hãy thử điều này 1. Thêm hệ thống tham chiếu.Giao dịch;

using(TransactionScope scope = new TransactionScope()) 
{ 
     //Initialize connection 
     // execute command 
    : 
    : 
    scope.Complete(); 
} 

Viết toàn bộ logic chèn/cập nhật bên trong phạm vi sử dụng. Điều này chắc chắn sẽ giúp bạn.

+0

Tôi không muốn những phụ trang này được cam kết như là một phần của giao dịch. Mã này là một phần của công việc chèn các mục công việc vào hàng đợi để xử lý sau này. Việc xử lý đó có thể xảy ra ngay lập tức và không đồng bộ, do đó mỗi hàng cần phải có sẵn để đọc càng sớm càng tốt. Nếu tất cả các chèn được gói trong một giao dịch, không có mục nào trong hàng đợi sẽ có sẵn cho đến khi toàn bộ công việc hoàn thành, do đó lãng phí thời gian. Tệ hơn nữa, nếu tôi thay đổi 'IsolationLevel' để cho phép đọc dơ bẩn, một sự quay trở lại sẽ tàn phá những thứ được xếp hàng đã được thực hiện sẽ biến mất! – josh3736

+0

Thử thêm Application.DoEvents(); hoặc Thread.Sleep (100) sau i + + –

+0

Tôi đánh giá cao đề xuất của bạn, nhưng tôi không nghĩ chúng có liên quan. Mã này không phải là một phần của ứng dụng Winforms; 'System.Windows.Forms.Application.DoEvents()' không tồn tại trong Windows Service. Hơn nữa, tôi không thấy cách bơm các thông điệp Windows liên quan đến một kết nối cơ sở dữ liệu (dù sao công việc này vẫn chạy trên luồng riêng của nó). Tôi cũng không thấy làm thế nào 'Thread.Sleep()' làm bất cứ điều gì nhưng làm chậm công việc của tôi. 100 ms * 25.000 hàng = ~ 42 ** phút ** ngủ - không tốt. – josh3736

0

Thêm phần sau đây sau khi tạo Lệnh của bạn.

cmd.CommandTimeout = 0; 

Điều này sẽ đặt CommandTimeout thành vô thời hạn. Lý do bạn nhận được một thời gian chờ có lẽ là do kết nối mặc dù thực hiện, vẫn còn trong giai đoạn 'lệnh' vì Reader.

Hoặc thử đặt CommandTimeout = 0 hoặc đọc mọi thứ trước, sau đó thực hiện các chức năng tiếp theo trên kết quả. Nếu không, vấn đề khác duy nhất tôi có thể couldy thấy là Sql Server là thả tập kết quả chống lại quá trình quy định id do một thời gian chờ trên máy chủ chính nó.

+1

'CommandTimeout' không ảnh hưởng đến việc truyền dữ liệu tới' DataReader'. Nó thực sự chỉ áp dụng cho lượng thời gian mà câu lệnh SQL có thể thực thi trên máy chủ. Khi câu lệnh hoàn thành (và 'MySqlCommand.ExecuteReader()' trả về), giá trị timeout sẽ không liên quan; bạn có thể mất miễn là bạn cần phải lặp qua các hàng được trả về bằng cách sử dụng 'MySqlDataReader.Read()'. Xem [câu trả lời này] (http://stackoverflow.com/questions/1484027/ado-net-datareader-timeout-issue/1484138#1484138) để biết thêm. Ngoài ra, tôi có thể biết điều này là ** không ** thời gian chờ vì không có ngoại lệ nào bị ném. – josh3736

0

tôi đã tìm thấy một bài báo ở đây http://corengen.wordpress.com/2010/06/09/mysql-connectornet-hangs-on-mysqldatareader-read/

gì anh chàng này trải qua một cái gì đó tương tự: a treo trên phương pháp đọc ở chính xác cùng một thời điểm, trong việc đọc của cùng một kỷ lục (đó là điều tương tự bạn kinh nghiệm tôi đoán). Trong trường hợp của mình, anh ta gọi một webservice khác trong vòng Read(), và cái đó đã hết thời gian làm cho Read() bị treo mà không có ngoại lệ.

Nó có thể giống nhau ở máy của bạn hay không, cập nhật trong vòng lặp Đọc() hết thời gian (tôi nghĩ bản cập nhật đó sử dụng thời gian chờ mặc định là 30 giây) và có tác dụng tương tự không?

Có thể là một cảnh quay dài, nhưng đọc hai câu chuyện có vẻ là rất nhiều familiair.

+0

Bài viết thú vị. Tuy nhiên, tôi không nghĩ rằng tôi đang bị treo cổ. Vòng lặp chạy tốt ở tốc độ không đổi lên tới bản ghi 14896 và sau đó 'Read()' chỉ trả về false - không có treo hoặc trì hoãn. – josh3736

2

Có lẽ bạn có bảng bị hỏng - vấn đề của anh chàng này nghe rất giống với bảng của bạn: http://forums.asp.net/t/1507319.aspx?PageIndex=2 - sửa bảng và xem điều gì sẽ xảy ra.

Nếu điều đó không làm việc, hãy đọc tiếp:

tôi đoán là bạn đang đánh một số loại Deadlock, đặc biệt là xem xét bạn đang đọc và viết. Điều này sẽ giải thích tại sao nó hoạt động với vòng lặp đơn giản, nhưng không hoạt động khi bạn cập nhật. Nó cũng sẽ giải thích lý do tại sao nó xảy ra xung quanh cùng một hàng/thời gian mỗi lần.

Đã xảy ra lỗi lạ trong SqlDataReader có ngoại lệ viết hoa (http://support.microsoft.com/kb/316667). Có thể có một cái gì đó tương tự trong MySqlDatareader - Sau cuộc gọi cuối cùng .Read() của bạn, hãy thử gọi .NextResult(). Ngay cả khi nó không phải là bế tắc, nó có thể giúp bạn chẩn đoán vấn đề. Trong loại tình huống này, bạn muốn nghiêng về "tin cậy nhưng xác minh" - vâng, tài liệu nói rằng và ngoại lệ sẽ được ném vào thời gian chờ, nhưng đôi khi (rất hiếm khi) tài liệu đó nằm :) Điều này đặc biệt đúng đối với bên thứ 3 nhà cung cấp - ví dụ xem http://bugs.mysql.com/bug.php?id=53439 - thư viện mysql .net đã có một số vấn đề như bạn đang gặp phải trong quá khứ.

Một ý tưởng khác là để xem những gì đang xảy ra trong cơ sở dữ liệu của bạn - hãy đảm bảo dữ liệu được tìm nạp liên tục cho tới hàng mà mã của bạn thoát.

Nếu không, tôi sẽ đọc tất cả dữ liệu, lưu vào bộ nhớ cache và sau đó thực hiện các sửa đổi của bạn. Bằng cách trộn các sửa đổi, mã sẽ ít trò chuyện và thực thi nhanh hơn.

Ngoài ra, thiết lập lại người đọc mỗi 1000 hoặc lâu hơn hàng (và theo dõi những gì ID hàng bạn đã lên đến)

Hope một cái gì đó ở đây sẽ giúp bạn với sự thất vọng của bạn! :)

+0

Điều sửa chữa bàn là đầy hứa hẹn, nhưng thử nó trên bảng InnoDB của tôi dẫn đến "Công cụ lưu trữ cho bảng không hỗ trợ sửa chữa." Vì vậy, không có súc sắc. Vì tôi đang đọc từ một bảng ('People') và viết cho một bảng khác (' Queue'), một tình huống bế tắc dường như không chắc. Tôi đã thử thêm một cuộc gọi đến cả 'Read()' và 'NextResult()' sau vòng lặp của tôi; cả hai đều trả về false. (Tôi mong đợi sai từ 'NextResult()' - chỉ có một truy vấn trong lệnh và do đó một resultset.) Tại thời điểm này, tôi khá thuyết phục rằng một ngoại lệ đang bị nuốt chửng ở đâu đó trong 'Read()'. – josh3736

+0

hóa ra có một ngoại lệ bị nuốt phải. Xem cập nhật cho câu hỏi của tôi. – josh3736

+0

Cool :) Bây giờ bạn đang nhận được một nơi nào đó. Có lẽ nó là để làm với kết nối tổng hợp - là bạn đóng kết nối của bạn mỗi khi bạn làm một bản cập nhật, hoặc tạo ra những cái mới mỗi lần? Hãy thử chuyển sang pooling = false để xác minh xem đó có phải là một số loại vấn đề tổng hợp hay không. http://bugs.mysql.com/bug.php?id=6634 dường như là chuỗi thích hợp. Nếu không, có lẽ bạn có một số hàng trả lại rất nhiều dữ liệu? bất kỳ dữ liệu nhị phân cột nào? Có tường lửa nào giữa máy chủ ứng dụng/máy chủ web và máy chủ cơ sở dữ liệu không? –

1

Có 2 vấn đề mà làm cho mọi việc khó hiểu hơn một chút so với nó nên là:

Đầu tiên, như đã được đề cập trong bài khác, đó là phiên bản cũ của đầu nối MySQL NET được nuốt một ngoại lệ timeout . Tôi đã sử dụng phiên bản 6.1.x mysql.data.dll và sau khi nâng cấp lên 6.3.6 ngoại lệ đã được ném đúng cách.

Thứ hai là mặc định timeout máy chủ MySQL, đặc biệt net_read_timeoutnet_write_timeout (mà mặc định là 30 và 60 giây tương ứng).

Với các phiên bản cũ hơn của mysql.data.dll, khi bạn đang thực hiện một hành động với dữ liệu trong vòng lặp datareader và bạn vượt quá thời gian chờ mặc định là 60 giây, chỉ cần ngồi đó và không làm gì cả. Với các phiên bản mới hơn, nó sẽ ném một ngoại lệ hết thời gian chờ giúp chẩn đoán sự cố.

Hy vọng điều này sẽ giúp ai đó khi tôi tình cờ gặp vấn đề này, nhưng giải pháp là sử dụng một cách tiếp cận khác, không phải là nguyên nhân/sửa chữa thực tế.

 

TLDR: Việc sửa chữa là tăng net_read_timeoutnet_write_timeout trên máy chủ mysql trong my.ini mặc dù nâng cấp mysql.data.dll là một ý tưởng tốt.

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