File Excel khi làm rất nặng

  • Thread starter Thread starter haiwang
  • Ngày gửi Ngày gửi
Liên hệ QC
Mình tìm trên này thấy đoạn code này xóa name được:

Sub DeleteErrName()
On Error Resume Next
Dim NSh As Name, i As Integer
Dim OldStatus As Boolean, ThongBao As String
OldStatus = Application.DisplayStatusBar
Sheets.Add.Name = "ShName"
For Each NSh In ActiveWorkbook.Names
If InStr(1, NSh.RefersToR1C1, "#") > 0 Or _
InStr(1, NSh.RefersToR1C1, "\") > 0 Then
i = i + 1
Application.StatusBar = "Deleted : " & Format(i, "#,##0") & _
" Deleting...: " & NSh.Name
Sheets("ShName").Range("A" & i).Value = NSh.Name
Sheets("ShName").Range("B" & i).Value = " " & NSh.RefersToR1C1
NSh.Delete
End If
Next
If i > 0 Then _
ThongBao = ThongBao & Chr(13) & Chr(13) & " -" & Format(i, "#,##0") & " Names da xoa"

MsgBox ThongBao, vbInformation, "GPE"

Application.StatusBar = ""
Application.DisplayStatusBar = OldStatus
End Sub
 
Mình xem qua rồi chắc tại bạn thêm quá nhiều đối tượng form trong Object đó thôi Google
 
Nếu bạn vẫn muốn delete một loạt thì nên làm ngược từ số lớn trở về số nhỏ - với hy vọng tránh được tình trạng index hoặc bộ nhớ bị sắp xếp lại thường xuyên

Mình nghĩ cũng không cần, Code của mình:
Mã:
Sub DelObjects()
  Dim i As Long, wks As Worksheet
  On Error Resume Next
  Set wks = ActiveSheet
  For i = 1 To 10000
    wks.Shapes([COLOR=#ff0000][/COLOR][SIZE=4][COLOR=#ff0000][B]1[/B][/COLOR][/SIZE]).Delete
  Next
  MsgBox "Còn " & wks.Shapes.Count & " objects"
End Sub
Cái màu đỏ là số 1 chứ hổng phải chữ i nha. Bạn nghĩ nó hợp lý chứ
 
Mình nghĩ cũng không cần, Code của mình:
Mã:
Sub DelObjects()
  Dim i As Long, wks As Worksheet
  On Error Resume Next
  Set wks = ActiveSheet
  For i = 1 To 10000
    wks.Shapes([SIZE=4][COLOR=#ff0000][B]1[/B][/COLOR][/SIZE]).Delete
  Next
  MsgBox "Còn " & wks.Shapes.Count & " objects"
End Sub
Cái màu đỏ là số 1 chứ hổng phải chữ i nha. Bạn nghĩ nó hợp lý chứ

Không phải tôi nói nó đúng hay không đúng.
Theo tôi suy diễn (không chắc là đúng, bởi vậy trước đó tôi có dùng từ "hy vọng") thì:
- Mỗi lần nó xoá đi phần tử số 1 thì các phần tử 2, 3, ... được đôn lên.
- Mỗi lần đôn như thế có thể tốn năng lượng.
Sự tốn năng lượng kể trên chỉ là ước phỏng. Nếu bên trong máy, các phần tử được xếp theo dạng nối đuôi vòng (circular queue) thì xoá đầu hay xoá đuôi không khác nhau bao nhiêu bởi vì việc xoá được thực hiện bằng cách dời con trỏ (tương tự như offset)
 
Không phải tôi nói nó đúng hay không đúng.
Theo tôi suy diễn (không chắc là đúng, bởi vậy trước đó tôi có dùng từ "hy vọng") thì:
- Mỗi lần nó xoá đi phần tử số 1 thì các phần tử 2, 3, ... được đôn lên.
- Mỗi lần đôn như thế có thể tốn năng lượng.
Sự tốn năng lượng kể trên chỉ là ước phỏng. Nếu bên trong máy, các phần tử được xếp theo dạng nối đuôi vòng (circular queue) thì xoá đầu hay xoá đuôi không khác nhau bao nhiêu bởi vì việc xoá được thực hiện bằng cách dời con trỏ (tương tự như offset)

Chính vì thế mà xóa đuôi luôn là bài bản. Vì xóa đuôi không bao giờ có chuyện dồn lên, còn xóa đầu có thể có dồn lên.
Trong Delphi có component TStringList mà phương thức Delete của nó là (Delphi source code)

Mã:
procedure TStringList.Delete(Index: Integer);
begin
  if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
  Changing;
  Finalize(FList^[Index]);
  Dec(FCount);
  if [B][COLOR=#0000ff]Index < FCount[/COLOR][/B] then
    [B][COLOR=#ff0000]System.Move(FList^[Index + 1], FList^[Index],
      (FCount - Index) * SizeOf(TStringItem));[/COLOR][/B]
  Changed;
end;

Chỗ đỏ đỏ chính là chỗ dồn lên, được thực hiện khi xóa phần tử không là cuối.
Vậy vd. ta có danh sách 10000 string mà ta xóa 5000 string cuối thì:

1. Xóa 5000 lần phần tử 5001 --> có 5000 lần thực hiện đỏ đỏ
2. Xóa 5000 lần phần tử cuối, tức xóa phần tử 10000, 9999, 9998, ..., 5001 --> đỏ đỏ không thực hiện lần nào.
 
Khi dùng lệnh xóa các phần tử thì nên xóa từ phần tử cuối như các bác nói trên là bài bản rồi. Còn việc chạy vòng lặp For Each luôn duyệt từ đầu đến cuối chứ không chạy ngược lại được. Vậy có thể dùng các loại vòng lặp còn lại và cho chạy lùi là được.
 
Trong VBA thì cái này phải thí nghiệm mới tin à nghen. Để xem sao cái
Ẹc... Ẹc...

Đồng ý 100%.
Chính vì vậy mà tôi vẫn nhét thêm trạng từ "hy vọng" (hopefully) và "có thể" (perhaps).
Bác Siwtom cũng dùng từ "bài bản". Theo tôi hiểu thì bác ấy muốn nói "nên làm, chứ không bắt buộc phải làm".
 
Bác Siwtom cũng dùng từ "bài bản". Theo tôi hiểu thì bác ấy muốn nói "nên làm, chứ không bắt buộc phải làm".

Thì ý là thế.

Trích
Cũng có thể bỏ từng em thứ 1 nhưng như thế thì sau mỗi lần bỏ thì toàn bộ "hàng hiện hành" phải dịch lên đầu 1 "chỗ".

Tôi tin chắc rằng nếu ai có máy mạnh thì có thể test 2 kiểu delete và theo tôi kiểu luôn delete cuối là nhanh hơn.

Chỗ đỏ đỏ có ý là cả 2 cách đều được, đều không sai.
 
Để kiểm trả tốc độ em có thử code này với file HHHHHHHHHHHH.xlsx
Code thứ nhất
Mã:
Sub test()
Dim k As Long, TG As Double, i As Long
TG = Timer
k = ActiveSheet.Shapes.Count
For i = 1 To k
    ActiveSheet.Shapes(1).Delete
Next
[L1] = Timer - TG
End Sub
Cho thời gian là 182 giây trên máy em
Code thứ 2
Mã:
Sub test()
Dim TG As Double, k As Long, wks As Worksheet
TG = Timer
Set wks = ActiveSheet
k = wks.Shapes.Count
Do While k > 0
    wks.Shapes(k).Delete
    k = k - 1
Loop
[K1].Value = Timer - TG
End Sub
Cho thời gian 470s trên máy em
Trong khi đó test thử từng shape thì thấy nó làm việc như sau:
Em Test thử 4 shapes theo thứ tự vẽ từng shape 1 và đánh số 1 đến 4 rồi dùng code ActiveSheet.Shapes(1).Delete thì shape 1 delete mất, chạy lần nữa Shape 2 delete mất chứng tỏ nó có sự sắp xếp lại

Tương tự Em Test thử vẽ 1 shapes rồi copy shape đó thành nhiều shapes đánh số 1 đến 4 rồi dùng code ActiveSheet.Shapes(1).Delete thì shape 1 delete mất, chạy lần nữa Shape 2 delete mất chứng tỏ nó có sự sắp xếp lại

Em Test ngược vẽ 4 shape dùng code Activesheet.Shapes(4) thì Shape 4 biến mất tiếp ActiveSheet.Shapes(3) thì Shapes(3) mất chứng tỏ nó không có sắp xếp lại

Mà khi test code lại kết quả sắp xếp lại nhanh hơn sắp xếp lại????? +-+-+-+
 
Đồng ý 100%.
Chính vì vậy mà tôi vẫn nhét thêm trạng từ "hy vọng" (hopefully) và "có thể" (perhaps).
Bác Siwtom cũng dùng từ "bài bản". Theo tôi hiểu thì bác ấy muốn nói "nên làm, chứ không bắt buộc phải làm".

Sở dĩ tôi nghi ngờ là vì chợt nghĩ ra một tình huống thế này:
- Trên sheet có 20000 shape
- Điều hiển nhiên là Excel sẽ gán cho 1 shape nào đó là giá trị Index =1 và 1 cái nào đó là giá trị Index = 20000
- Bây giờ nếu tôi xóa bằng tay Shape mang index =1 thì hóa ra nó sẽ "chậm" hơn so với khi tôi xóa thằng shape mang index = 20000 (theo suy luận của bạn)
Tôi thì lại cảm thấy nó vô lý vô cùng ấy chứ ???!!!
Xin lỗi, vì tôi chỉ học mò nên cũng nói theo kiểu mò và dùng thực nghiệm để kiểm chứng thôi
 
Sở dĩ tôi nghi ngờ là vì chợt nghĩ ra một tình huống thế này:
- Trên sheet có 20000 shape
- Điều hiển nhiên là Excel sẽ gán cho 1 shape nào đó là giá trị Index =1 và 1 cái nào đó là giá trị Index = 20000
- Bây giờ nếu tôi xóa bằng tay Shape mang index =1 thì hóa ra nó sẽ "chậm" hơn so với khi tôi xóa thằng shape mang index = 20000 (theo suy luận của bạn)
Tôi thì lại cảm thấy nó vô lý vô cùng ấy chứ ???!!!
Xin lỗi, vì tôi chỉ học mò nên cũng nói theo kiểu mò và dùng thực nghiệm để kiểm chứng thôi

Vấn đề nằm ở lý thuyết cấu trúc dữ liệu.

Shapes là một collection. Hàm Shapes(i) là một hàm dùng chỉ số i để lấy về phần tử ở vị trí i của collection này.
Cái mà tôi chưa nắm vững là Excel/VBA dùng kỹ thuật nào để lập cấu trúc dữ liệu cho cái shapes collection.

1. Nếu collection này diễn theo dạng array thì:
- Collection chứa địa chỉ đầu mảng.
- Khi xoá phần tử đầu, các phần tử khác sẽ được đôn lên. Vì vậy tốn năng lượng. Tuy nhiên,

2. Nếu collection này diễn theo dang danh sách liên kết thì:
- Con trỏ collection trỏ vào phần tử đầu danh sách.
- Khi xoá phần tử đầu, collection chỉ việc mò đến phần tử kế tiếp, dời con trỏ vào đấy và vứt bỏ phần tử đàu tiên.
- Khi xoá phần tử cuối, collection phải mò từ đầu đến cuối để vứt bó phần tử cuối. Vì vậy ngược lại cách này lại tốn năng lượng hơn cách xoá phần tử đầu.

3. Nếu diễn theo kỹ thuật khác: chưa biết. Nhưng nếu là kỹ thuật bảng tra thì ý của bạn là đúng.

Chú thích cho những bạn ít có tiếp xúc với cơ cấu dữ liệu:

Đối với array, các phần tử được xếp liên tục nhau trong bộ nhớ. Hàm (), tức là hàm dùng chỉ số để tìm phần tử, sử dụng con toán nhân trực tiếp (nhân chỉ số với số bytes của loại dữ liệu) để biết offset giữa phần tử này và phần tử đầu mảng.

Đối với danh sách liên kết hay liinked list, các phần từ không được xếp liên tục nhau trong bộ nhớ. Chúng liên hệ với nhau bằng cách mỗi phần tử (gọi là nút) chứa một con trỏ cho biết địa chỉ của phần tử kế nó. DSLK chỉ cần biết địa chỉ phần tử đầu tiên. Vì vậy DSLK không có con toán trực tiếp liên hệ giữa chỉ số và địa chỉ phần tử. Hàm () phải phăng từ phần tử đầu tiên cho đến phần tử cần kiếm.

Đối với bảng tra (indexed table), các phần tử cũng không liên tục nhau trong bộ nhớ. Hệ thống dùng một bảng tra (thường là bảng b-tree) để chứa địa chỉ từng phần tử. Đối với loại này, năng lượng xoá phần tử liên hệ trực tiếp đến sự cân bằng của bảng tra chứ không quan hệ mấy với vị trí phần tử.
 
Lần chỉnh sửa cuối:
\

Chú thích cho những bạn ít có tiếp xúc với cơ cấu dữ liệu:

Đối với array, các phần tử được xếp liên tục nhau trong bộ nhớ. Hàm (), tức là hàm dùng chỉ số để tìm phần tử, sử dụng con toán nhân trực tiếp (nhân chỉ số với số bytes của loại dữ liệu) để biết offset giữa phần tử này và phần tử đầu mảng.

Đối với danh sách liên kết hay liinked list, các phần từ không được xếp liên tục nhau trong bộ nhớ. Chúng liên hệ với nhau bằng cách mỗi phần tử (gọi là nút) chứa một con trỏ cho biết địa chỉ của phần tử kế nó. DSLK chỉ cần biết địa chỉ phần tử đầu tiên. Vì vậy DSLK không có con toán trực tiếp liên hệ giữa chỉ số và địa chỉ phần tử. Hàm () phải phăng từ phần tử đầu tiên cho đến phần tử cần kiếm.

Đối với bảng tra (indexed table), các phần tử cũng không liên tục nhau trong bộ nhớ. Hệ thống dùng một bảng tra (thường là bảng b-tree) để chứa địa chỉ từng phần tử. Đối với loại này, năng lượng xoá phần tử liên hệ trực tiếp đến sự cân bằng của bảng tra chứ không quan hệ mấy với vị trí phần tử.

Nói thật lòng: Đọc đến chỗ này là mình xem như... ngu luôn rồi ---> Hết biết gì ráo
Nhưng dù sao vẫn cảm ơn bạn, vì bây giờ không biết, biết đâu mai này sẽ biết
Ẹc... Ẹc...
 
Xin chân thành cảm ơn các anh chị đã giúp đỡ mình :)
 
Bác nào nghiên cứu thời gian chạy cho các thuật toán xóa Shape khác nhau để tìm code tối ưu luôn đi.
 
Web KT

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

Back
Top Bottom