PDA

View Full Version : Procedure xu ly dl cho 65.000 records



freebirds
02-06-2006, 14:06
+ Client + Server kết nối LAN
+ CSDL SQL Server 2000
+ Viết Store Procedure xử lý dữ liệu (tính toán và cập nhập dữ liệu khá phức tạp) cho 65000 records.
+ Gọi procedure trên client để thực hiện tính toán.

Nếu chia nhỏ ra để tính toán (tức là tính toán cho khoang 300 records mỗi lần) thì thời gian tính không chênh lệch là bao (khoảng 30s) --> 65000 records mất khoang 1h.

Nhưng khi tôi test thử tính toán cho 65000 records, có lúc procedure hoàn thành trong 1 tiếng.
Lúc lại gần 10 tiếng mới xong
Và lúc thì chẳng biết bao jo xong.
Ai có kinh nghiệm xin chỉ giáo...

lannguyen
02-06-2006, 15:27
Nên dùng Index trong MS SQL để tăng tốc độ, xem books online về INDEX.

freebirds
02-06-2006, 16:00
Đã làm thử nhưng hiệu quả không nhiều. Vấn đền ở đây là trên cùng 1 dữ liệu mà thời gian xử lý lại khác nhau (Open 1 cursor và thực hiện mọi tính toán trong 1 vòng lặp duy nhất)

mtt333
02-06-2006, 16:05
+ Client + Server kết nối LAN
Nếu chia nhỏ ra để tính toán (tức là tính toán cho khoang 300 records mỗi lần) thì thời gian tính không chênh lệch là bao (khoảng 30s) --> 65000 records mất khoang 1h.

Nhưng khi tôi test thử tính toán cho 65000 records, có lúc procedure hoàn thành trong 1 tiếng.
Lúc lại gần 10 tiếng mới xong
Và lúc thì chẳng biết bao jo xong.
Ai có kinh nghiệm xin chỉ giáo...

Nếu không có nhu cầu quá gay gắt về đồng bộ CSDL cho 65000 bản ghi đó trong một transaction thì chia nhỏ làm 300 một lần là phương án rất tốt. Hơn nữa khả năng commit và rollback cũng đã đảm bảo tính đồng bộ dữ liệu cho 65000 bản ghi rùi.

Trong trường hợp nảy sinh yêu cầu phải đồng bộ ngay 1 lần 65000 bản ghi trong 1 transaction thì nên kiểm tra lại thiết kế: CSDL và chức năng chương trình xem liệu có thể chuyển sang phương án chia nhỏ được không.

Chuyện cập nhật một lúc 65000 bản ghi tiêu tốn nhiều tài nguyên hệ thống: bộ nhớ đệm, liên tục kiểm tra ràng buộc trong 65000 bản ghi mà chưa đựoc đánh chỉ mục nên tốc độ kiểm ra lâu, nó cũng giống như việc bạn chạy một chương trình ngốn bộ nhớ 1GB trên máy PC trong 1 lần chạy (ví dụ hình tượng thế), toàn bộ hệ thống sẽ ì ạch, chạy mất ổn định, khi có sai thì phải rất lâu mới thông báo mà lỡ sai thì hỏng luôn cả lô 65000 bản ghi và lại phải chạy lại hệ thống ì ạch từ đầu. Không một nhà thiết kế chương trình nào làm thế, hoạn chia bộ nhớ mà chương tình sẽ lấn chiếm ra làm nhiều mảnh, dùng đến đâu nạp vào bộ nhớ đến đó, dùng mảnh nào xong thì giải phóng bộ nhớ, chuyển tạm ra một vùng đệm trên đĩa cứng.

Hơn nữa, về mặt giao diện người sử dụng, họ không thích thực hiện một lúc 65000 bản ghi rùi ngồi chờ dài cổ mà chả biết cái gì đang diễn ra, họ thích được thông báo lại bằng một cái thông báo: đã thực hiện bao nhiêu bản ghi, còn lại bao nhiêu trong số 65000 bản ghi đó hoặc phải có 1 cái progress bar hiển thị bao nhiều % thực hiện được, cái này chí ít nếu làm một lúc 65000 bản ghi thì không thực hiện được (ít nhất trong những tip về kỹ thuật mà mình biết).

Sử dụng index chỉ tăng tốc độ tìm kiếm lên, nếu cập nhật vào trường được đánh index thì tốc độ còn lâu nữa. Vấn đề của freebirds không phải la vấn đề của tốc độ tìm kiếm, 65000 bản ghi tìm kiếm vấn nhanh, nhưng cập nhật một lúc tất cả 65000 bản ghi là một vấn đề lớn.

tn1908
02-06-2006, 22:05
(Open 1 cursor và thực hiện mọi tính toán trong 1 vòng lặp duy nhất)
Day la nguyen nhan chinh lam cho thu tuc cua ban chay cham. Neu thu tuc lien quan den cap nhat nhieu bang, ban nen tim cach dung update/join de cap nhat ca bang trong 1 lenh update (hoac chia lam vai lenh nhu moi nguoi da goi y). Neu chi la cap nhat tren 1 bang, co the ban nen tinh den export ra text file roi dung 1 chuong trinh C/Perl de xu ly, roi import nguoc lai vao sql server
(ko hieu sao ko danh duoc tieng Viet)

The Old Man
02-06-2006, 23:51
+ Client + Server kết nối LAN
+ Viết Store Procedure xử lý dữ liệu (tính toán và cập nhập dữ liệu khá phức tạp) cho 65000 records.
+ Gọi procedure trên client để thực hiện tính toán.

Tiếng Việt về tin học tôi không rành lắm và về các từ như xử lý dữ liệu v.v. tôi không quen lắm nhưng tôi có kinh nghiệm về database. Với tôi 65000 records không phải là số lớn. Tôi thường lập trình cho các cơ sở dữ liệu có số lượng lớn hơn rất nhiều (vài trăm ngàn records).
Nếu phải update information cho một database có 65000 records, mỗi records cho rằng có 100 field names thì tôi nghỉ rằng không quá 15 phút (theo tôi thì hơn 5 phút là lâu rồi) là xong. Đương nhiên là đã có kể tới tính toán điều kiện này nọ hơi phức tạp chút.
Tôi không hiểu là cái module hay procedure bạn cho client chạy được viết như thế nào nên không dám bàn luận nhiều, chỉ nói tới vài chi tiết bạn nên để ý khi Network programming:
Khi muốn cập nhập dữ liệu (update record) thì nên nhớ là đang trong Network record phải lock thì mới update được. Ví dụ có người khác trong mạng đang dùng cái record đó thì bạn không thể update được. Vì vậy khi lock record đễ update, khi update xong cho record đó thì phải unlock record đó ngay.
Tôi xin dùng thí dụ của Xbase cho một procedure update 1 record:

goto 15 // tìm tới record số 15 hay locate for
if reclock(5) // nếu khoá được (không có ai dùng tới record này) trong vòng 5 giây
replace field1 with " tin tức mới cũa field 1"
replace field2 with " tin tức mới cũa field 2"
replace field3 with " tin tức mới cũa field 3" // và tiếp tục cho hết những field cần update
unlock() // mở khoá ngay
else
msgalert("Có người đang mở hồ sơ"," Báo cáo") // thông báo là không update được record.
endif
Cách này dùng khi share data trong mạng với các client khác.

Cách của database Admin
Nếu muốn lẹ hơn thì lock nguyên database rồi update record qua loop do while mà không phải reclock ()hay unlock()
cách này dùng khi không có ai (client) dùng database. Thường dùng ngoài giờ làm việc (System maintenance)

Một yếu tố nửa về thời gian phải cần chú ý là cách dùng index. Nếu sử dụng đúng cách thì indexing có thể rút thời gian update lại rất nhiều (có khi giảm được 70,80 % thời gian tuỳ theo điều kiện xử lý ).
Nếu dùng Index không đúng chỗ thì ngược lại tốn thời gian lâu hơn cả chục lần, nhiều khi bị rơi vào loop thì chờ forever.

Thật ra thời gian update hết một database không cần biết có bao nhiêu record trong đó bằng thời gian copy database file vào một folder khác (tức là thời gian viết lại toàn thể database) cộng với thời gian tính toán điều kiện cho mỗi record (thủ thuật lập trình).
Vì thế nếu bạn update 65000 record mà trên 1 tiếng là Procedure của bạn có vấn đề. Ngay cả generate report cho 65000 hồ sơ cũng không lâu đến thế.

freebirds
05-06-2006, 14:04
Tiếng Việt về tin học tôi không rành lắm và về các từ như xử lý dữ liệu v.v. tôi không quen lắm nhưng tôi có kinh nghiệm về database. Với tôi 65000 records không phải là số lớn. Tôi thường lập trình cho các cơ sở dữ liệu có số lượng lớn hơn rất nhiều (vài trăm ngàn records).
Nếu phải update information cho một database có 65000 records, mỗi records cho rằng có 100 field names thì tôi nghỉ rằng không quá 15 phút (theo tôi thì hơn 5 phút là lâu rồi) là xong. Đương nhiên là đã có kể tới tính toán điều kiện này nọ hơi phức tạp chút.
Tôi không hiểu là cái module hay procedure bạn cho client chạy được viết như thế nào nên không dám bàn luận nhiều, chỉ nói tới vài chi tiết bạn nên để ý khi Network programming:
Khi muốn cập nhập dữ liệu (update record) thì nên nhớ là đang trong Network record phải lock thì mới update được. Ví dụ có người khác trong mạng đang dùng cái record đó thì bạn không thể update được. Vì vậy khi lock record đễ update, khi update xong cho record đó thì phải unlock record đó ngay.
Tôi xin dùng thí dụ của Xbase cho một procedure update 1 record:

goto 15 // tìm tới record số 15 hay locate for
if reclock(5) // nếu khoá được (không có ai dùng tới record này) trong vòng 5 giây
replace field1 with " tin tức mới cũa field 1"
replace field2 with " tin tức mới cũa field 2"
replace field3 with " tin tức mới cũa field 3" // và tiếp tục cho hết những field cần update
unlock() // mở khoá ngay
else
msgalert("Có người đang mở hồ sơ"," Báo cáo") // thông báo là không update được record.
endif
Cách này dùng khi share data trong mạng với các client khác.

Cách của database Admin
Nếu muốn lẹ hơn thì lock nguyên database rồi update record qua loop do while mà không phải reclock ()hay unlock()
cách này dùng khi không có ai (client) dùng database. Thường dùng ngoài giờ làm việc (System maintenance)

Một yếu tố nửa về thời gian phải cần chú ý là cách dùng index. Nếu sử dụng đúng cách thì indexing có thể rút thời gian update lại rất nhiều (có khi giảm được 70,80 % thời gian tuỳ theo điều kiện xử lý ).
Nếu dùng Index không đúng chỗ thì ngược lại tốn thời gian lâu hơn cả chục lần, nhiều khi bị rơi vào loop thì chờ forever.

Thật ra thời gian update hết một database không cần biết có bao nhiêu record trong đó bằng thời gian copy database file vào một folder khác (tức là thời gian viết lại toàn thể database) cộng với thời gian tính toán điều kiện cho mỗi record (thủ thuật lập trình).
Vì thế nếu bạn update 65000 record mà trên 1 tiếng là Procedure của bạn có vấn đề. Ngay cả generate report cho 65000 hồ sơ cũng không lâu đến thế.

Rất cám ơn các bạn đã chia sẻ.
Tôi nói xử lý dữ liệu cho 65000 bản ghi là vì tôi ko biết phải sử dụng từ gì cho hợp lý (do mình không chuyên về database :D).
Từ 65000 bản ghi trong bảng Contract + dữ liệu trong tập hợp các bảng liên quan đến Formula (công thức tính toán) + dữ liệu của bảng liên quan đến lượng tiêu thụ của khách hàng trong tháng --> tính toán + tạo ra 2 bảng dl để thể hiện chi tiết các khoản tiền mà khách hàng phải trả trong tháng và 1 số dữ liệu khác liên quan.
Hoàn tất công việc trên, tiếp tục tạo ra 2 bảng dữ liệu tháng nữa
(cái này do thiết kế yêu cầu. Tôi cũng chẳng hiểu để lam gì :D)

Đúng la tính toán cho 300 records mất hơn 30s tôi cung thấy rất chậm.
Cách xử lý của The Old Man tôi chưa từng làm. Hy vọng sẽ có hiệu quả. Sau đợt này chắc có chút xíu kinh nghiệm về database :D

foxes_lover
01-09-2006, 10:41
Tôi đã từng thao tác tính toán trên CSDL SQL 2000 với hàng trăm nghìn bản ghi. Kết quả cũng không đến nỗi vậy mặc dù việc xử lý cũng không hề nhỏ. Kinh nghiệm của tôi thế này, chúng ta cùng trao đổi nhé:
- Việc sử dụng Cursor trên một khối lượng dữ liệu lớn là hết sức hạn chế, kết quả thử nghiệm trên vài chục nghìn dòng dữ liệu khi dùng và không dùng Cursor là chênh lệch nhau về tốc độ khoảng 10 đến 60 lần. Có thể thay thế Cursor bằng những bảng tạm có chứa các Identity rồi tham chiếu (join table), tốc độ sẽ cải thiện đáng kể. Chỉ dùng Cursor khi ko còn cách nào khác.
- Đặt Set nocount on và set nocount off để ngăn ngừa việc tạo nhiều kết nối Client-Server
- Tối ưu lại thuật toán và tune lại CSDL, bao gồm cả về dữ liệu lẫn câu lệnh
- Còn vấn đề thời gian thực thi khác nhau trên cùng bộ DL thì tôi cũng đã gặp phải, tuy nhiên chưa rõ nguyên nhân.
Hy vọng ý kiến của tôi sẽ giúp được bạn phần nào. Rất mong được mọi người góp ý và trao đổi.

QUOCDN
01-09-2006, 20:39
Trong Oracle,có khái niệm segment extent và block data, đối với dư xliệu lớn, bạn nên định vị theo segment, khi các segment đầy O sẽ tự động định vị seggmênt khác. Một segment lại lưu trong tablespace...
Trong SQL Server có khái niệm con trỏ, bạn hãy xác định rõ khối dữ liệu này(bội số của kích thước khối HĐH mà ta đang dùng trong giới hạn tối đa), và của Oracle; không tính kích thước của index, table, hay dữ liệu cluster.
Định vị cho bằng được các segment của table hay cluster hay segment index của một index, không gian trống có thể giữu trong trasaction.

Lưu ý: Trước một giao tác cập nhật, xóa hay chèn trong một khối không gian thực tế yêu cầu cho 1 segment là 23 byte. Chỉ có 23!!

Cần phân tích chính xác như sau:

Trong trường hợp thứ 1, khi lần 1 chèn vào, row quá lớn không vừa trong 1 segment, O sẽ chứa trong 1 chuỗi khối dl.

Trường hợp 2, 1 hàng lúc đầu nằm trong 1 khối dl, sau đó được cập nhật và chiều dài tăng lên mà bạn thấy không gian trống hết. Khi này cần khái niệm di trú, tăng hiệu năng I/O, Extent tạo nên bởi một khối dữ liệu liên tục .

QUOCDN
01-09-2006, 20:47
Hy vọng 2 trường hựp phân tích trên của tôi sẽ thỏa mãn được câu hỏi bài toán của bạn !

xbacala
01-09-2006, 22:34
Bạn này nói có vẽ hay quá nhưng có 1 số điểm tui không rõ, muốn học hỏi thêm:


1. Trong Oracle,có khái niệm segment extent và block data, đối với dư xliệu lớn, bạn nên định vị theo segment, khi các segment đầy O sẽ tự động định vị seggmênt khác

=> định vị theo segment là thế nào? và tại sao nên ?



2. Trong SQL Server có khái niệm con trỏ, bạn hãy xác định rõ khối dữ liệu này(bội số của kích thước khối HĐH mà ta đang dùng trong giới hạn tối đa), và của Oracle; không tính kích thước của index, table, hay dữ liệu cluster.

=> Làm sao xác định được con trỏ trong SQL và khối dữ liệu của nó ?


3. Định vị cho bằng được các segment của table hay cluster hay segment index của một index, không gian trống có thể giữu trong trasaction.

=> How?


4. Trước một giao tác cập nhật, xóa hay chèn trong một khối không gian thực tế yêu cầu cho 1 segment là 23 byte. Chỉ có 23!!

=> Con số 23 này ở đâu ra, tui chưa tùng biết bao giờ. Cái này cho SQL hay Oracle ?


5. Trong trường hợp thứ 1, khi lần 1 chèn vào, row quá lớn không vừa trong 1 segment, O sẽ chứa trong 1 chuỗi khối dl.

=> Khi chèn vào thì O allocate data cho row theo block hay theo segment? theo bạn nói thì 1 row sẽ chứa trong 1 segment?



6. Trường hợp 2, 1 hàng lúc đầu nằm trong 1 khối dl, sau đó được cập nhật và chiều dài tăng lên mà bạn thấy không gian trống hết. Khi này cần khái niệm di trú, tăng hiệu năng I/O, Extent tạo nên bởi một khối dữ liệu liên tục

=> Cái này trừu tượng quá 0 hiểu

QUOCDN
02-09-2006, 14:52
BO SUNG :
1. Khi bantao 1 bang trong Oracle, se dinh vi cho segment du lieu của table 1 extent dau tien gom 1 so nhat dinh (kich thuoc thiet lap duoc), Du ch chua co hang nao chen vao trong bang nhung khoi du lieu trong extent dau tien duoc danh rieng cho cac hang cua bang do.
2. segment la phan doan . 1 segment la tap cac extent duco dinh vi cho 1 loai CAU TRUC CSDL dac biet. Ex: vi du du lieu cua ban co du lieu thung se luu vo segment cua chinh no, con du lieu bang hay index duoc phan chia, moi phan phan chia như (partition trong chia dia) duoc luu trong segment cua table hay index do.

3. SEGMENT VA TAT CA EXTENT CUA NO SE LUU TRONG TABLESPACE
4. khi ban dung cluster trong thiet ke bang, ban can xac dinh ro : cluster la mot nhom cac bang co cung khoi du lieu do chung co cac cot chung va thong su dung chung voi nhau . Dat biet rang buoc toan ven du lieu (integrity constraint). Do cach luu tru cluster cac hang lien quan cua cac bang khac nhau trong cung 1 khoi du lieu( data block) do vay :
=> I/O dík giam, cai thien thoi gian truy cap nho ket noi cac bang cluster. Cac cluster key chi luu 1 lan duy nhat ,vi du nhu DEPT_NO cua bang DEPT luu 1 lan duy nhat cho ca 2 bang EMP VA DEPT.

Hy vong giai thich nhu vay bang se ro trong cac practices cua mình!!!

QUOCDN
02-09-2006, 15:00
Khong gian trong
Khong gian trong dung de chen 1 hang moi va cap nhat acc rơ yeu cau them du lieu(vd: khi 1 gia tri null duoc cap nhat thanh gia tri notnull). KHong gian yeu cau doi voi mot diem chuyen tac khoang 23byte.
Trong SQL Server : "Đặt Set nocount on và set nocount off để ngăn ngừa việc tạo nhiều kết nối Client-Server" nhu reply ben tren cung la ` giai phap de giam i/o giua client server.

vqt
05-10-2006, 05:27
Hi,

Bạn cần nên tìm hiểu lý do tại sao nó chạy chậm rồi mới có hướng giải quyết.

Nếu thời gian thực hiện công việc tỷ lệ thuận một cách gần tuyến tính với khối lượng dữ liệu thì là chuyện bình thường. Trong trường hợp của bạn thì nó lại không như vậy. Theo ý kiến chủ quan của tôi thì bạn nên xem xét bộ nhớ cung cấp cho nó. Cụ thể là RAM, HDD và kích thước file data, file log có đủ không. (Đôi khi chỉ cần chạy defrag HDD cũng có thể giải quyết được vấn đề) Theo tôi bạn nên khoanh vùng từng vấn đề một thì sẽ tìm được nguyên nhân và cách khắc phục.