2012-09-07 27 views
6

tôi đang kéo url từ cơ sở dữ liệu của tôi với một kịch bản perl nơi mà tôi sử dụng fetchrow_array để kéo URL từ cơ sở dữ liệu mà làm việc tốt cho đến khi tôi gặp một URL rất dài georgelog24.blog.iskreni.net/?bid=6744d9dcf85991ed2e4b8a258153a1ab&lid=ff9963b9a798ea335b75b5f7c0c295d1
sau đó nó bắt đầu cho tôi lỗi nàyCơ sở dữ liệu fetchrow_array thất bại dài cắt ngắn DBI thuộc tính

DBD::ODBC::st fetchrow_array failed: st_fetch/SQLFetch (long truncated DBI attribute LongTruncOk not set and/or LongReadLen too small) (SQL-HY000) [state was HY000 now 01004] 
[Microsoft][ODBC SQL Server Driver]String data, right truncation (SQL-01004) at C:\test\multihashtest2.pl line 44. 

Tôi tin rằng đây là bên phía cơ sở dữ liệu vì mã tôi đang sử dụng để kéo URL đã hoạt động trước đó. Cơ sở dữ liệu mà tôi đang sử dụng là MSSQL Server 2005.

cột URL trong cơ sở dữ liệu sử dụng văn bản loại hiện được, nhưng tôi đã cố gắng thay đổi nó để varchar (max)nvarchar (max) nhưng lỗi vẫn tồn tại.

Sau một chút thử và sai, tôi thấy rằng độ dài tối đa của url sau đó tôi có thể truy vấn thành công với fetchrow_array là 81 ký tự. Và vì URL có thể kéo dài độ dài vô lý đôi khi, tôi không thể đặt giới hạn về độ dài URL.

Ai đó có thể giúp tôi hiểu và đề xuất khắc phục sự cố này không?

FYI: dòng 44 là dòng đầu tiên trong mã của tôi dưới đây

while (($myid,$url) = $statement_handle->fetchrow_array()) { # executes as many threads as there are jobs to do 
    my $thread = threads->create(\&webcrawl); #initiate thread 
    my $tid = $thread->tid; 
    print " - Thread $tid started\n"; #obtain thread no. and print 
    push (@Threads, $thread); #push thread into array for "housekeeping" later on 
} 

Trả lời

5

Hãy nhìn vào DBI thuộc tính LongTruncOkLongReadlen

Bạn sẽ cần phải hoặc là chấp nhận cắt ngắn hoặc thiết lập một kích thước tối đa dưới dạng văn bản và varchar (max) cột có thể được lớn vì vậy nếu nó đã được trái DBD nó sẽ không có sự lựa chọn, nhưng để phân bổ số lượng lớn của bộ nhớ trong trường hợp cột là kích thước tối đa của cột đó.

10

Hãy thử với:

#not anymore errors if content is truncated - you don't necessarily want this 
$statement_handle->{'LongTruncOk'} = 1; 

#nice, hard coded constant for the length of data to be read from Longs 
$statement_handle->{'LongReadLen'} = 20000; 
while (($myid,$url) = $statement_handle->fetchrow_array()) { # executes as many threads as there are jobs to do 
    my $thread = threads->create(\&webcrawl); #initiate thread 
    my $tid = $thread->tid; 
    print " - Thread $tid started\n"; #obtain thread no. and print 
    push (@Threads, $thread); #push thread into array for "housekeeping" later on 
} 

Ngoài ra, tôi muốn khuyên bạn nên thử Parallel::ForkManager cho parallelizing công việc - Tôi thấy nó rất trực quan và dễ sử dụng hơn so với đề

+0

Cảm ơn bạn đã xây dựng thêm về cách áp dụng LongReadLen. ForkManager có vẻ dễ hơn chủ đề. Hầu như là một semaphore và thread của nó kết hợp. –

+1

Btw, giống như phần bổ sung, http://search.cpan.org/~timb/DBI-1.622/DBI.pm#LongReadLen. Thay đổi giá trị của 'LongReadLen' cho một lệnh xử lý sau khi nó đã được' chuẩn bị' sẽ thường không có hiệu lực, do đó, nó thường đặt 'LongReadLen' trên' $ dbh' trước khi gọi 'chuẩn bị'. – stenlytw

3

điểm quan trọng: bạn cần đặt thuộc tính LongReadLen và/hoặc LongTruncOk trên cơ sở dữ liệu xử lýtrước để chuẩn bị tuyên bố, như được ghi chú here.

Cố gắng đặt thiết bị trên bảng điều khiển tuyên bố đã chuẩn bị trước khi tìm nạp dữ liệu sẽ không ảnh hưởng đến việc cắt bớt dữ liệu được trả về.

+0

Cảm ơn. Đây là giải pháp để thực hiện công việc này. –

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