Giúp cải tiến tốc độ xử lý (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

thanhduc_iit

Thành viên chính thức
Tham gia
2/4/11
Bài viết
55
Được thích
2
Chào các bác,
Hiện em có tạo 1 file excel gộp nhiều file excel, và thống kê
Nhưng chạy quá chậm. Em post lên đây nhờ các bác cải tiến để tốc độ cải thiện ạ.
File chạy là Phan bo KCB, bấm CHỌN DỮ LIỆU để chọn nhiều file excel đưa vào và được tổng hợp qua sheet Kết quả.
Rất mong nhận được sự giúp đỡ}}}}}
 
Lần chỉnh sửa cuối:
Chào các bác,
Hiện em có tạo 1 file excel gộp nhiều file excel, và thống kê
Nhưng chạy quá chậm. Em post lên đây nhờ các bác cải tiến để tốc độ cải thiện ạ.
File chạy là Phan bo KCB, bấm CHỌN DỮ LIỆU để chọn nhiều file excel đưa vào và được tổng hợp qua sheet Kết quả.
Rất mong nhận được sự giúp đỡ}}}}}
Có 1 số thắc mắc như sau:
- Sheet Hộp đen là sheet để chứa tất cả các sheet có trong các file đưa vào? Mục đích là gì?
- Các file cần gộp có bao nhiêu sheet, cấu trúc có giống nhau hay không? Tên sheet có thể giống nhau?
- Điều kiện để ra Sheet Ket qua? Lấy từ sheet Hộp đen qua? Chỉ có thỏa điều kiên 2 cột tô màu vàng (ma_tinh, ma_bv). Còn các cột còn lại của sheet Ket qua được lấy từ đâu?
 
Upvote 0
Có 1 số thắc mắc như sau:
- Sheet Hộp đen là sheet để chứa tất cả các sheet có trong các file đưa vào? Mục đích là gì?
- Các file cần gộp có bao nhiêu sheet, cấu trúc có giống nhau hay không? Tên sheet có thể giống nhau?
- Điều kiện để ra Sheet Ket qua? Lấy từ sheet Hộp đen qua? Chỉ có thỏa điều kiên 2 cột tô màu vàng (ma_tinh, ma_bv). Còn các cột còn lại của sheet Ket qua được lấy từ đâu?
Mục đích là gộp nhiều file excel riêng lẽ thành 1 file duy nhất và đếm
- Sheet Hộp đen nhằm mục đích chứa tất cả dữ liệu được copy từ các file được chọn.
- Các file đưa vào đều có 1 sheet duy nhất. Cấu trúc sheet đưa vào đều giống cấu trúc, tên sheet giống tên file (vì trong chương trình xuất ra).
- Sheet kết quả nhằm mục đích thống kê theo ma_tinh, ma_bv lấy dữ liệu từ sheet Hộp đen
+ ma_tinh:
nếu trống thì hiểu là '93
+ ma_bv:
kết hợp với ma_tinh để biết là bệnh viện nào ('01001 là Bệnh viện Hữu Nghị, '93007 là Bệnh viện đa khoa TP Vị Thanh...)
+ Ở sheet Kết quả chỉ cần tính cột Số lượt, các cột khác đã là text có sẳn
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
sheet Kết quả đó bác Hai Lúa
Sheet Hộp đen sau khi làm xong, em ẩn nó đi rồi--=0
Tôi chưa hiểu yêu cầu ở sheet kết quả nên tôi chỉ làm cho bạn phần gộp file = ADO

[GPECODE=sql]Sub GopFile()
Dim cn As Object, adoRS As Object
Dim i As Integer, endR As Integer
Dim strFileName As Variant, shtName As String
strFileName = Application.GetOpenFilename("Excel Files (*.xl*), *.xl*", _
Title:="Select files", MultiSelect:=True)
If IsArray(strFileName) Then
Set cn = CreateObject("ADODB.Connection")
Set adoRS = CreateObject("ADODB.Recordset")
For i = LBound(strFileName) To UBound(strFileName)
shtName = Replace(Mid(strFileName(i), InStrRev(strFileName(i), "\") + 1), ".xls", "$")
With cn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & strFileName(i) & _
";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
.Open
End With
With adoRS
.ActiveConnection = cn
.Open "SELECT * FROM [" & shtName & "]"
endR = Sheet2.Range("B65000").End(xlUp).Row + 1
Application.ScreenUpdating = False
Sheet2.Range("A" & endR).CopyFromRecordset adoRS
Application.ScreenUpdating = True
.Close
cn.Close
End With
Next i
End If
Set cn = Nothing: Set adoRS = Nothing
Set strFileName = Nothing

End Sub

[/GPECODE]
 

File đính kèm

Upvote 0
Bị lỗi này bác ạ
overflow.png


Em chạy cùng dữ liệu bằg code của em (xin của 1 bác trên diễn đàn) thì k sao hết ạ
Code của bác chạy thì không thấy mở file, ADO có vẻ nhanh hơn
 
Upvote 0
Bị lỗi này bác ạ
overflow.png


Em chạy cùng dữ liệu bằg code của em (xin của 1 bác trên diễn đàn) thì k sao hết ạ
Code của bác chạy thì không thấy mở file, ADO có vẻ nhanh hơn

Là code bị lỗi? nếu lỗi thì sao có khẳng định đo đỏ ở trên.
 
Upvote 0
Là code bị lỗi? nếu lỗi thì sao có khẳng định đo đỏ ở trên.
Em đã test thử khoảng 20 file thì code của bác nhanh hơn. Và lúc chạy chỉ chóp chóp màn hình, k thấy mở file.
Còn code có sẳn trong file của em thì chậm hơn. Chóp màn hình, thấy mở file rồi đóng.
Của em có 295 file bác ạ!$@!! Bác có thể chỉnh lại code chạy k lỗi được k?}}}}}

Em test lại đến đoạn bị lỗi. Test với 82 file excel:
+Code ADO của bác: 8:09 giây
+Code của em: 11:98 giây
 
Lần chỉnh sửa cuối:
Upvote 0
Em đã test thử khoảng 20 file thì code của bác nhanh hơn. Và lúc chạy chỉ chóp chóp màn hình, k thấy mở file.
Còn code có sẳn trong file của em thì chậm hơn. Chóp màn hình, thấy mở file rồi đóng.
Của em có 295 file bác ạ!$@!! Bác có thể chỉnh lại code chạy k lỗi được k?}}}}}

Em test lại đến đoạn bị lỗi. Test với 82 file excel:
+Code ADO của bác: 8:09 giây
+Code của em: 11:98 giây
Số lượng 295 file * số dòng trong 1 file = bao nhiêu dòng vậy bạn?
 
Upvote 0
Theo mình nếu sheet hộp đen không dùng lưu trữ data mà chỉ để làm trung gian để tính thì để tránh tràn bộ nhớ thay vì copy dữ liệu vào sheet hộp đen, bạn tính luôn số mã thẻ theo từng bệnh viện rồi đưa cộng vào kết quả cũ trong sheet.
 
Upvote 0
Theo mình nếu sheet hộp đen không dùng lưu trữ data mà chỉ để làm trung gian để tính thì để tránh tràn bộ nhớ thay vì copy dữ liệu vào sheet hộp đen, bạn tính luôn số mã thẻ theo từng bệnh viện rồi đưa cộng vào kết quả cũ trong sheet.
Tại vì em gà VBA nên lấy sheet Hộp đen là trung gian chứa dữ liệu.
Sheet Kết quả nhằm mục đích đếm bệnh viện ở sheet Hộp đen
 
Upvote 0
Tại vì em gà VBA nên lấy sheet Hộp đen là trung gian chứa dữ liệu.
Sheet Kết quả nhằm mục đích đếm bệnh viện ở sheet Hộp đen
Để đếm số bệnh viện, bạn thử code sau
Mã:
Sub ketqua()
Dim a(), b(), r As Range, s As Range, cell As Range
    Set r = Sheets(2).UsedRange.Columns(17)
    Set s = Sheets(3).UsedRange.Offset(1).Columns(3)
    ReDim a(1 To r.Rows.Count)
    ReDim b(1 To s.Rows.Count, 1 To 1)
    For i = 1 To UBound(a)
        If r.Cells(i) <> "" Then a(i) = r.Cells(i) & r.Cells(i).Offset(, 1) _
        Else a(i) = "93" & r.Cells(i).Offset(, 1)
    Next
        b = s.Value
For j = 1 To UBound(b)
        c = 0
    For i = 1 To UBound(a)
        If b(j, 1) = a(i) Then c = c + 1
    Next
        If c = 0 Then b(j, 1) = "" Else b(j, 1) = c
Next
        s.Offset(, 2).Value = b
End Sub
 
Upvote 0
Để đếm số bệnh viện, bạn thử code sau
Mã:
Sub ketqua()
Dim a(), b(), r As Range, s As Range, cell As Range
    Set r = Sheets(2).UsedRange.Columns(17)
    Set s = Sheets(3).UsedRange.Offset(1).Columns(3)
    ReDim a(1 To r.Rows.Count)
    ReDim b(1 To s.Rows.Count, 1 To 1)
    For i = 1 To UBound(a)
        If r.Cells(i) <> "" Then a(i) = r.Cells(i) & r.Cells(i).Offset(, 1) _
        Else a(i) = "93" & r.Cells(i).Offset(, 1)
    Next
        b = s.Value
For j = 1 To UBound(b)
        c = 0
    For i = 1 To UBound(a)
        If b(j, 1) = a(i) Then c = c + 1
    Next
        If c = 0 Then b(j, 1) = "" Else b(j, 1) = c
Next
        s.Offset(, 2).Value = b
End Sub

Em dùng hàm COUTIFS nó chạy chậm quá@#!^%
 
Lần chỉnh sửa cuối:
Upvote 0
Code này làm đổi dữ liệu ở sheet Hộp đen bác ạ (cột ma_bv)

Sử dụng file gốc của em, chèn thêm Nút gắn code ở trên bài #14 thì ok bác ạ/-*+/
Vấn đề là em chưa thể tăng tốc gộp nhiều file excel

Không đổi gì cả, đó là mã tôi tự gõ vào để thử thôi
 
Upvote 0
Không đổi gì cả, đó là mã tôi tự gõ vào để thử thôi
Trong file em thấy GopFile(), em dùng thử thì chạy được 1 lút thì báo lỗi như bác Hai Lúa Miền Tây//**/

Cảm ơn mấy bác đã nhiệt tình giúp đỡ!
Giờ thì cũng đã đáp ứng được yêu cầu của em rồi: copy nhiều file excel thành 1 file và đếm/-*+/
Nhưng em thấy giải thuật thì chưa ổn lắm, tốc độ thực thi còn chậm.
-Em thì không biết được code copy có chính xác tuyệt đối hay không vì dữ liệu lớn quá////// 295 file, khoảng 40.000 dòng
-Code đếm của bác nginh như thế cũng ổn rồi/-*+/
Nếu được thì các bác giúp em thêm 1 bước nữa nhé, là khi đếm xong ẩn đi những dòng giá trị bằng 0 luôn đi ạ//**/
 
Lần chỉnh sửa cuối:
Upvote 0
Trong file em thấy GopFile(), em dùng thử thì chạy được 1 lút thì báo lỗi như bác Hai Lúa Miền Tây//**/

Cảm ơn mấy bác đã nhiệt tình giúp đỡ!
Giờ thì cũng đã đáp ứng được yêu cầu của em rồi: copy nhiều file excel thành 1 file và đếm/-*+/
Nhưng em thấy giải thuật thì chưa ổn lắm, tốc độ thực thi còn chậm.
-Em thì không biết được code copy có chính xác tuyệt đối hay không vì dữ liệu lớn quá////// 295 file, khoảng 40.000 dòng
-Code đếm của bác nginh như thế cũng ổn rồi/-*+/
Nếu được thì các bác giúp em thêm 1 bước nữa nhé, là khi đếm xong ẩn đi những dòng giá trị bằng 0 luôn đi ạ//**/

Bạn thêm đoạn sau vào ngay trước End Sub
Mã:
        For Each cell In s.Offset(, 2).Cells
            If cell = "" Then cell.EntireRow.Hidden = True
        Next
 
Upvote 0
Trong file em thấy GopFile(), em dùng thử thì chạy được 1 lút thì báo lỗi như bác Hai Lúa Miền Tây//**/

Cảm ơn mấy bác đã nhiệt tình giúp đỡ!
Giờ thì cũng đã đáp ứng được yêu cầu của em rồi: copy nhiều file excel thành 1 file và đếm/-*+/
Nhưng em thấy giải thuật thì chưa ổn lắm, tốc độ thực thi còn chậm.
-Em thì không biết được code copy có chính xác tuyệt đối hay không vì dữ liệu lớn quá////// 295 file, khoảng 40.000 dòng
-Code đếm của bác nginh như thế cũng ổn rồi/-*+/
Nếu được thì các bác giúp em thêm 1 bước nữa nhé, là khi đếm xong ẩn đi những dòng giá trị bằng 0 luôn đi ạ//**/

Thật tình mà nói tôi theo dõi đề tài này cũng đã lâu nhưng chỉ hiểu đến đoạn bạn muốn gộp file vào 1 sheet, vậy xin hỏi bạn cái kết quả gộp đó dùng với mục đích gì? Nếu bạn giải thích kỹ hơn chắc có lẽ sẽ có giải pháp khác tối ưu hơn.

Bạn test thử code sau coi còn lỗi không nhé.
[GPECODE=sql]Sub GopFile()
Dim cn As Object, adoRS As Object
Dim i As Integer, strSQL As String
Dim strFileName As Variant, shtName As String
strFileName = Application.GetOpenFilename("Excel Files (*.xl*), *.xl*", _
Title:="Select files", MultiSelect:=True)
If IsArray(strFileName) Then
Set cn = CreateObject("ADODB.Connection")
Set adoRS = CreateObject("ADODB.Recordset")
For i = LBound(strFileName) To UBound(strFileName)
shtName = Replace(Mid(strFileName(i), InStrRev(strFileName(i), "\") + 1), ".xls", "$")
strSQL = strSQL & " SELECT * FROM [" & strFileName(i) & "].[" & shtName & "] union all "
Next i
With cn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & ThisWorkbook.FullName & _
";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
.Open
End With
With adoRS
.ActiveConnection = cn
.Open Left(strSQL, Len(strSQL) - 10)
Sheet2.Range("A2").CopyFromRecordset adoRS
.Close
End With
End If
cn.Close
Set cn = Nothing: Set adoRS = Nothing
Set strFileName = Nothing

End Sub

[/GPECODE]
 
Lần chỉnh sửa cuối:
Upvote 0
Thật tình mà nói tôi theo dõi đề tài này cũng đã lâu nhưng chỉ hiểu đến đoạn bạn muốn gộp file vào 1 sheet, vậy xin hỏi bạn cái kết quả gộp đó dùng với mục đích gì? Nếu bạn giải thích kỹ hơn chắc có lẽ sẽ có giải pháp khác tối ưu hơn.
File dữ liệu cần gộp vào chứa các trường ma_tỉnh và ma_bv. Mỗi cơ sở khám chữa bệnh bảo hiểm y tế trên toàn quốc có một mã duy nhất gồm 5 ký tự: ma_tinh 2 chữ số, ma_bv 3 ký tự (thường là 3 chữ số). Bảng ở sheet kết quả chứa tất cả mã này.
Mỗi người tham gia BHYT được cấp thẻ, trên thẻ có mã thẻ (có 15 ký tự) và mã cơ sở khám chữa bệnh ban đầu (gồm 5 ký tự ở trên). Dữ liệu vào có các trường: sokcb (chính là mã thẻ), ma_tinh, ma_bv.
Mục đích của tác giả là ứng với mỗi bệnh viện (xác định bởi ma_tinh và ma_bv, tên bệnh viện ở bảng kết quả), đếm xem có bao nhiêu thẻ đăng ký, sau đó điền vào sheet kết quả (không dùng công thức countifs ở cột số thẻ).
Ví dụ sau khi gộp dữ liệu ở sheet Hộp đen, gọi bảng dữ liệu ở sheet này là HD, bảng ở sheet kết quả là KQ.
-Lệnh đếm số thẻ ở bảng HD là
Select ma_tinh, ma_bv, Count(sokcb) As so_the From HD Group By ma_tinh, ma_bv
Lưu kết quả này vào bảng tạm là DEM.
- Lệnh điền vào bảng kết quả là (lệnh này cũng chỉ lấy những bệnh viện có số thẻ >0 do DEM.so_the>0)
Select KQ.mabv, KQ.ten_bv, DEM.so_the From KQ Inner Join DEM On (KQ.ma_bv=DEM.ma_bv) And (KQ.ma_tinh=DEM.ma_tinh)
(lệnh này cũng chỉ lấy những bệnh viện có số thẻ >0 do DEM.so_the>0)
- Có thể dùng subquerry để kết hợp 2 lệnh trên.
- Mình không biết về ADO nên không test được các lệnh trên có cải thiện tốc độ không (chắc là không, mình làm thử mấy lệnh SQL đơn giản với data lớn thấy rất lâu). Nếu import vào Visual Foxpro thì tốc độ sẽ cải thiện rất nhiều, mình dùng Select đơn giản với file database khoảng 30000 record chỉ mất khoảng vài giây.
 
Lần chỉnh sửa cuối:
Upvote 0
File dữ liệu cần gộp vào chứa các trường ma_tỉnh và ma_bv. Mỗi cơ sở khám chữa bệnh bảo hiểm y tế trên toàn quốc có một mã duy nhất gồm 5 ký tự: ma_tinh 2 chữ số, ma_bv 3 ký tự (thường là 3 chữ số). Bảng ở sheet kết quả chứa tất cả mã này.
Mỗi người tham gia BHYT được cấp thẻ, trên thẻ có mã thẻ (có 15 ký tự) và mã cơ sở khám chữa bệnh ban đầu (gồm 5 ký tự ở trên). Dữ liệu vào có các trường: sokcb (chính là mã thẻ), ma_tinh, ma_bv.
Mục đích của tác giả là ứng với mỗi bệnh viện (xác định bởi ma_tinh và ma_bv, tên bệnh viện ở bảng kết quả), đếm xem có bao nhiêu thẻ đăng ký, sau đó điền vào sheet kết quả (không dùng công thức countifs ở cột số thẻ).
Ví dụ sau khi gộp dữ liệu ở sheet Hộp đen, gọi bảng dữ liệu ở sheet này là HD, bảng ở sheet kết quả là KQ.
-Lệnh đếm số thẻ ở bảng HD là
Select ma_tinh, ma_bv, Count(sokcb) As so_the From HD Group By ma_tinh, ma_bv
Lưu kết quả này vào bảng tạm là DEM.
- Lệnh điền vào bảng kết quả là (lệnh này cũng chỉ lấy những bệnh viện có số thẻ >0 do DEM.so_the>0)
Select KQ.mabv, KQ.ten_bv, DEM.so_the From KQ Inner Join DEM On (KQ.ma_bv=DEM.ma_bv) And (KQ.ma_tinh=DEM.ma_tinh)
(lệnh này cũng chỉ lấy những bệnh viện có số thẻ >0 do DEM.so_the>0)
- Có thể dùng subquerry để kết hợp 2 lệnh trên.
- Mình không biết về ADO nên không test được các lệnh trên có cải thiện tốc độ không (chắc là không, mình làm thử mấy lệnh SQL đơn giản với data lớn thấy rất lâu). Nếu import vào Visual Foxpro thì tốc độ sẽ cải thiện rất nhiều, mình dùng Select đơn giản với file database khoảng 30000 record chỉ mất khoảng vài giây.

Nếu đúng như lời bạn giải thích thì không cần dùng sheet Hop den để gộp dữ liệu, điều này sẽ làm cho dung lượng file tăng lên đáng kể một cách không cần thiết.
Tôi có thể dùng ADO cho bài toán này với thời gian được tính toán từ lúc gộp cho đến ra kết quả trong vòng 4-5 giây cho 3 file mẫu gộp.
Dù sao cũng phải chờ tác giả xác nhận xem có phải như vậy hay là không.
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu đúng như lời bạn giải thích thì không cần dùng sheet Hop den để gộp dữ liệu, điều này sẽ làm cho dung lượng file tăng lên đáng kể một cách không cần thiết.
Tôi có thể dùng ADO cho bài toán này với thời gian được tính toán từ lúc gộp cho đến ra kết quả trong vòng 4-5 giây cho 3 file mẫu gộp.
Dù sao cũng phải chờ tác giả xác nhận xem có phải như vậy hay là không.
Đúng như vậy đấy, mình cũng làm trong ngành nên biết. Mình đang nghĩ 2 cách:
- Với mỗi file test, đếm số thẻ rồi dùng lệnh UPDATE để đưa vào bảng kết quả, cuối cùng cập nhật bảng kết quả vào sheet.
- Gộp tất cả file test vào 1 bảng, đếm rồi JOIN với bảng kết quả, cuối cùng cập nhật bảng kết quả vào sheet.
Cách 2 chắc sẽ nhanh hơn cách 1 nhưng nếu dữ liệu gộp lớn dễ tràn bộ nhớ, cách 1 thì chỉ tràn bộ nhớ khi gặp 1 file test có dữ liệu lớn.
 
Upvote 0
Nếu đúng như lời bạn giải thích thì không cần dùng sheet Hop den để gộp dữ liệu, điều này sẽ làm cho dung lượng file tăng lên đáng kể một cách không cần thiết.
Tôi có thể dùng ADO cho bài toán này với thời gian được tính toán từ lúc gộp cho đến ra kết quả trong vòng 4-5 giây cho 3 file mẫu gộp.
Dù sao cũng phải chờ tác giả xác nhận xem có phải như vậy hay là không.

Sau khi tôi bỏ những sheet không cần thiết, đặc biệt là sheet [Copy excel] thì code của tôi nó chạy cũng khá nhanh.

1.jpg
 
Upvote 0
Trước tiên em cảm ơn các bác đã quan tâm}}}}}
Yêu cầu của em đúng như bác Hau151978 trình bày rồi đó ạ
Và mấy ngày qua em cũng đã tích góp được thành 1 file hoàn chỉnh. Em gửi lên để các bác xem hộ.
Vấn đề là tốc độ thực thi với số lượng file lên đến khoảng 300 file, hơn 40.000 mẫu tin thì tốc độ còn khá chậm, khoảng 1phút30giây

Em dùng sheet Hộp đen để chứa dữ liệu được copy vì em định dùng hàm COUNTIFS để đếm nhưng sử dụng đến 15.238 hàm COUNTIFS để đếm cho 15.238 bệnh viện trên cả nước thì tốc độ cực chậm

PS bác Hai Lúa Miền Tây, em dùng code ở bài #21 thì bị lỗi này nếu chọn quá nhiều file bác ạ (289 files)
query is too complex.jpg
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Bạn chạy thử với lần lược với 4 lần là 250, 255, 256, 257 files thử rồi thông báo kết quả nhé.
Em đã test rất kỹ code của bác. Và kết quả như sau:
-Hộp thoại mở lên mà bấm Cancel (không chọn file) thì lỗi:
k chon file.png
PS: thêm 1 dòng này thì khắc phục được lỗi trên
Mã:
    On Error Resume Next
-Chọn hơn 50 file thì báo lỗi:
51.png
 
Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom