Tìm kích thước không nén của tất cả các bảng trong cơ sở dữ liệu


12

Trong Dynamics AX có một cơ chế lưu trữ trong đó các bảng có thể được cấu hình để được tải vào bộ nhớ và lưu vào bộ đệm. Bộ đệm này được giới hạn ở một lượng KB nhất định để ngăn ngừa các vấn đề về bộ nhớ. Cài đặt tôi đang nói đến được gọi entiretablecachevà tải toàn bộ bảng trong bộ nhớ ngay khi một bản ghi được yêu cầu.

Gần đây, chúng tôi đã dựa vào một số tập lệnh để xác minh kích thước của các bảng có cài đặt này để xem kích thước bảng có vượt quá giới hạn này không.

Tuy nhiên, bây giờ, nén đã phát huy tác dụng và những thứ như sp_spaceuse hoặc sys.allocation_units dường như báo cáo không gian thực sự được sử dụng bởi dữ liệu nén.

Rõ ràng, máy chủ ứng dụng đang làm việc với dữ liệu không nén nên kích thước dữ liệu trên đĩa trong SQL Server là không liên quan. Tôi cần kích thước thực tế dữ liệu không nén sẽ có.

Tôi biết về sp_estimate_data_compression_savings nhưng như tên gọi, đây chỉ là ước tính.
Tôi muốn có kích thước càng chính xác càng tốt.

Cách duy nhất tôi có thể nghĩ đến là một số SQL động phức tạp tạo các bảng không nén có cùng cấu trúc với các bảng được nén, chèn dữ liệu nén vào bảng bóng đó và sau đó kiểm tra kích thước của bảng bóng đó.
Không cần phải nói, điều này là một chút tẻ nhạt và mất một thời gian để chạy trên cơ sở dữ liệu vài trăm GB.

Powershell có thể là một tùy chọn, nhưng tôi không muốn lặp lại tất cả các bảng để thực hiện select *trên chúng để kiểm tra kích thước trong tập lệnh vì điều đó sẽ làm ngập bộ đệm và có lẽ cũng sẽ mất nhiều thời gian.

Nói tóm lại, tôi cần một cách để có được kích thước cho mỗi bảng vì nó sẽ không bị nén và bị phân mảnh khỏi phương trình như được trình bày cho ứng dụng, nếu điều đó có thể. Tôi cởi mở với các cách tiếp cận khác nhau, T-SQL được ưa thích nhưng tôi không phản đối Powershell hoặc các cách tiếp cận sáng tạo khác.

Giả sử bộ đệm trong ứng dụng là kích thước của dữ liệu. Một bigint luôn có kích thước của một bigint và một kiểu dữ liệu ký tự là 2 byte cho mỗi ký tự (unicode). Dữ liệu BLOB cũng có kích thước của dữ liệu, enum về cơ bản là dữ liệu int và số là số (38,12), datetime là kích thước của datetime. Ngoài ra, không có NULLgiá trị, chúng được lưu trữ dưới dạng một chuỗi rỗng 1900-01-01hoặc bằng không.

Không có tài liệu nào về cách thực hiện, nhưng các giả định dựa trên một số thử nghiệm và tập lệnh được sử dụng bởi PFE và nhóm hỗ trợ (cũng bỏ qua việc nén rõ ràng, vì kiểm tra được xây dựng trong ứng dụng và ứng dụng không thể biết nếu dữ liệu cơ bản được nén) cũng kiểm tra kích thước bảng. Liên kết này cho ví dụ:

Tránh sử dụng bộ đệm EntireTable cho các bảng lớn (trong AX 2009 trên 128 KB hoặc 16 trang, trong AX 2012 trên cài đặt ứng dụng 'toàn bộ kích thước bộ đệm của bảng [mặc định: 32KB hoặc 4 trang]) - thay vào đó, hãy chuyển sang ghi bộ đệm.


3
Đó là hacky, nhưng có lẽ một bản sao được khôi phục với nén bị vô hiệu hóa sẽ là chính xác nhất. Sau đó, bạn cũng đang thử nghiệm khôi phục, điều này khiến bạn trông giống như một DBA HÀNG ĐẦU.
Erik Darling

Tin rằng đó sẽ là đặt cược tốt nhất của bạn. Có thể có cách để thử và làm toán. Có bao nhiêu hàng theo các kiểu dữ liệu và độ dài cột được xác định nhân lên sau đó thêm vào các chỉ mục, v.v. Nó hoạt động nhiều hơn so với kịch bản khôi phục và vô hiệu hóa nén @sp_BlitzErik gợi ý ở trên. Và ai sẽ không muốn trở thành một DBA HÀNG ĐẦU?
Mike Walsh

SUM (datalength ()) cho tất cả các cột có kích thước dữ liệu không nén?
Tapakah Ua

@sp_BlitzErik Đó có thể là câu trả lời thay vì nhận xét.
Tom V - thử topanswers.xyz

Câu trả lời:


7

Tôi cần kích thước thực tế dữ liệu không nén sẽ có.
...
Tôi muốn có kích thước càng chính xác càng tốt.

Mặc dù mong muốn về thông tin này chắc chắn là dễ hiểu, nhưng việc có được thông tin này, đặc biệt là trong bối cảnh "chính xác nhất có thể" là khó khăn hơn mọi người mong đợi do các giả định sai lầm. Cho dù thực hiện ý tưởng bảng bóng không nén được đề cập trong câu hỏi, hoặc đề xuất của @ sp_BlitzErik trong một nhận xét về việc khôi phục DB và giải nén ở đó để kiểm tra, không nên giả sử rằng kích thước của bảng không nén == kích thước của dữ liệu đã nói trong bộ nhớ trên máy chủ ứng dụng:

  1. Có phải tất cả các hàng trong bảng được lưu trữ? Hay chỉ trong một phạm vi? Giả định ở đây là tất cả, và điều đó có thể đúng, nhưng tôi đoán rằng ít nhất nên đề cập rằng đây có thể không phải là trường hợp (trừ khi tài liệu nói khác đi, nhưng dù sao đây chỉ là một điểm nhỏ, chỉ là không muốn nó không được đề cập).

    Câu hỏi đã được cập nhật thành trạng thái: có, tất cả các hàng đang được lưu trữ.

  2. Kết cấu

    1. Về phía DB:
      Trang và hàng ngang trên phía DB: Có bao nhiêu hàng vừa trên một trang được xác định bởi nhiều yếu tố có thể loại bỏ ước tính. Ngay cả với FILLFACTOR100 (hoặc 0), vẫn có khả năng vẫn còn một khoảng trống chưa sử dụng trên trang do nó không đủ cho toàn bộ một hàng. Và đó là ngoài tiêu đề trang. Ngoài ra, nếu bất kỳ chức năng Snapshot Isolation nào được bật, tôi tin rằng, sẽ có thêm 13 byte cho mỗi hàng được lấy bởi số phiên bản và điều đó sẽ loại bỏ ước tính. Có những chi tiết vụn vặt khác liên quan đến kích thước thực tế của hàng (bitmap NULL, cột có chiều dài thay đổi, v.v.) nhưng các mục được đề cập cho đến nay chỉ nên tạo ra điểm.
    2. Về phía máy chủ ứng dụng:
      Loại bộ sưu tập nào đang được sử dụng để lưu trữ các kết quả được lưu trong bộ nhớ cache? Tôi giả sử đây là một ứng dụng .NET, vậy nó có phải là một DataTable? Một danh sách chung? Một sắp xếp từ điển? Mỗi loại bộ sưu tập có một lượng khác nhau. Tôi sẽ không mong đợi bất kỳ tùy chọn nào nhất thiết phản ánh các chi phí của Trang và Hàng ở phía DB, đặc biệt là ở quy mô (Tôi chắc chắn một lượng nhỏ hàng có thể không đủ khác nhau để quan trọng, nhưng bạn không tìm kiếm sự khác biệt trong hàng trăm byte hoặc chỉ một vài kB).
  3. Loại dữ liệu
    1. Về phía DB:
      CHAR/ VARCHARdữ liệu được lưu trữ ở mức 1 byte cho mỗi ký tự (bỏ qua các ký tự hai byte trong thời điểm này). XMLđược tối ưu hóa để không chiếm nhiều không gian như cách trình bày văn bản sẽ ngụ ý. Kiểu dữ liệu này tạo ra một từ điển các tên thành phần và thuộc tính và thay thế các tham chiếu thực tế đến chúng trong tài liệu bằng ID tương ứng của chúng (thực sự khá tốt). Mặt khác, các giá trị chuỗi là tất cả UTF-16 (2 hoặc 4 byte cho mỗi "ký tự"), giống như NCHAR/ NVARCHAR. DATETIME2nằm trong khoảng từ 6 đến 8 byte. DECIMALnằm trong khoảng từ 5 đến 17 byte (tùy thuộc vào độ chính xác).
    2. Về phía máy chủ ứng dụng:
      Chuỗi (một lần nữa, giả sử .NET) luôn là UTF-16. Không có tối ưu hóa cho các chuỗi 8 bit như những gì VARCHARgiữ. NHƯNG, các chuỗi cũng có thể được "tập trung", đó là một bản sao được chia sẻ có thể được tham chiếu nhiều lần (nhưng tôi không biết liệu chuỗi này có hoạt động cho các chuỗi trong các bộ sưu tập hay không, nếu nó hoạt động cho tất cả các loại bộ sưu tập). XMLcó thể hoặc không thể được lưu trữ theo cùng một cách trong bộ nhớ (tôi sẽ phải tìm kiếm điều đó). DateTimeluôn luôn là 8 byte (như T-SQL DATETIME, nhưng không phải như DATE, TIMEhoặc DATETIME2). luôn luônDecimal16 byte .

Tất cả điều đó để nói: không có gì nhiều bạn có thể làm ở phía DB để có được kích thước dấu chân bộ nhớ khá chính xác ở phía máy chủ ứng dụng. Bạn cần tìm cách thẩm vấn chính máy chủ ứng dụng, sau khi được tải với một bảng cụ thể, vì vậy hãy biết nó lớn như thế nào. Và tôi không chắc chắn nếu một trình sửa lỗi sẽ cho phép bạn xem kích thước thời gian chạy của một bộ sưu tập đầy. Nếu không, cách duy nhất để đến gần là đi qua tất cả các hàng của bảng, nhân mỗi cột với kích thước .NET thích hợp (ví dụ INT= * 4, VARCHAR= DATALENGTH() * 2, NVARCHAR= DATALENGTH(), XML= 🙃, v.v.), nhưng điều đó vẫn để lại câu hỏi của chi phí chung của bộ sưu tập cộng với từng yếu tố của bộ sưu tập.

Đưa ra một số định nghĩa mới trong câu hỏi, có lẽ người ta có thể thực hiện truy vấn sau đây để đến gần hơn. Và không quan trọng việc bảng có được nén hay không, mặc dù tùy thuộc vào mỗi người để xác định xem việc quét tất cả các hàng có phù hợp với Sản xuất hay không (có thể thực hiện từ khôi phục hoặc trong giờ thấp điểm):

SELECT
   SUM( DATALENGTH([NVarcharColumn_1]) + DATALENGTH([NVarcharColumn_N]) ) + 
   SUM( (DATALENGTH([VarcharColumn_1]) + DATALENGTH([VarcharColumn_N])) * 2 ) + 
   SUM(4 * [number_of_INT_columns]) +
   SUM(8 * [number_of_BIGINT_and_DATETIME_columns]) +
   SUM(16 * [number_of_DECIMAL/NUMERIC_and_UNIQUEIDENTIFIER_columns]) +
   etc..
FROM [SchemaName].[TableName] WITH (NOLOCK) -- assuming no Snapshot Isolation

Nhưng hãy nhớ rằng, đây không phải là tài khoản cho bộ sưu tập hoặc phần tử bộ sưu tập. Và không chắc chắn liệu chúng ta có thể nhận được giá trị đó mà không cần trình gỡ lỗi hay không (hoặc có thể là một cái gì đó như ILSpy, nhưng tôi không khuyến nghị điều đó vì nó có thể vi phạm EULA tùy thuộc vào luật pháp địa phương).


Chúng tôi đã kết thúc việc thực hiện kiểm tra trong mã để chắc chắn về kích thước bộ đệm như được trình bày cho ứng dụng.
Tom V - thử topanswers.xyz

6

Từ câu hỏi của bạn, có vẻ như bạn có kích thước bộ đệm tối đa Svà bạn không muốn tải các bảng vào bộ đệm vượt quá kích thước đó. Nếu đó là sự thật thì bạn không cần phải biết kích thước chính xác của mỗi bảng. Bạn chỉ cần biết nếu một bảng lớn hơn hoặc nhỏ hơn kích thước bộ đệm tối đa S. Đó là một vấn đề dễ dàng hơn đáng kể tùy thuộc vào định nghĩa cột và số lượng hàng của bảng.

Tôi đồng ý với câu trả lời tuyệt vời của Solomon Rutzky khi nhìn vào dữ liệu không nén không phải là hướng đi và có thể khó đưa ra một xấp xỉ tốt cho kích thước thật của bảng trong bộ đệm. Tuy nhiên, tôi sẽ làm việc trong khuôn khổ câu hỏi và cho rằng bạn có thể phát triển một công thức đủ gần dựa trên định nghĩa cột cho các loại dữ liệu tĩnh và độ dài thực tế của các cột động của bạn.

Nếu bạn có ánh xạ các loại dữ liệu theo kích thước bộ đệm thì bạn có thể đánh giá một số bảng mà không cần nhìn vào dữ liệu trong đó:

  1. Nếu một bảng chỉ có các kiểu dữ liệu tĩnh (không có chuỗi hoặc đốm màu) thì bạn có thể tính gần đúng số lượng hàng bằng cách xem sys.partitionsvà tính kích thước của bảng bằng định nghĩa cột.
  2. Nếu một bảng có nhiều hàng có đủ các cột kiểu dữ liệu tĩnh thì bạn có thể loại bỏ nó quá lớn mà không cần nhìn vào dữ liệu của nó. Ví dụ: một bảng có 10 triệu hàng và 5 BIGINTcột có thể có kích thước của dữ liệu đó có kích thước là 10000000 * (8 + 8 + 8 + 8 + 8) = 400 M byte có thể lớn hơn giới hạn kích thước bộ đệm của bạn S. Không có vấn đề gì nếu nó có một loạt các cột chuỗi.
  3. Nếu một bảng có vài hàng đủ nhỏ thì bạn có thể xác nhận rằng nó nằm dưới giới hạn chỉ bằng cách giả sử rằng mỗi loại dữ liệu động có kích thước tối đa có thể. Ví dụ: bảng 100 hàng có BIGINTcột và NVARCHAR(20)cột không được vượt quá 100 * (8 + 2 * 20) = 4800 byte.
  4. Có thể đúng là nếu một bảng có kích thước nén trong SQL Server lớn hơn bởi một số yếu tố Sthì điều đó rất khó có thể phù hợp với bộ đệm. Bạn sẽ phải thực hiện kiểm tra để tìm ra nếu một giá trị như vậy tồn tại.
  5. Bạn có thể gặp may mắn khi tất cả các cột động xảy ra để có số liệu thống kê về chúng. Thống kê chứa thông tin về độ dài trung bình và có thể đủ chính xác cho mục đích của bạn.

Bạn có thể phải truy vấn dữ liệu của các bảng không phù hợp với bất kỳ tiêu chí nào ở trên. Có một số thủ thuật mà bạn có thể sử dụng để giảm thiểu tác động hiệu suất của việc này. Tôi muốn nói rằng bạn có hai ưu tiên cạnh tranh ở đây: bạn đánh giá cao độ chính xác nhưng cũng không muốn quét tất cả dữ liệu trong cơ sở dữ liệu của bạn. Có thể thêm một số loại bộ đệm vào tính toán của bạn. Tôi không biết có nên chấp nhận loại trừ một bảng dưới kích thước bộ đệm tối đa Shoặc chấp nhận một bảng cao hơn một chút so với kích thước bộ đệm tối đa.

Dưới đây là một số ý tưởng để làm cho các truy vấn xem dữ liệu bảng nhanh hơn:

  1. Đối với các bảng lớn, bạn có thể sử dụng TABLESAMPLEmiễn là cỡ mẫu của bạn đủ lớn.
  2. Đối với các bảng lớn có khóa phân cụm, có thể hữu ích để xử lý chúng theo lô trên khóa phân cụm. Thật không may, tôi không biết cách tính toán SUM()thoát ra sớm dựa trên giá trị của tổng hợp đó. Tôi chỉ từng thấy rằng làm việc cho ROW_NUMBER(). Nhưng bạn có thể quét 10% đầu tiên của bảng, lưu kích thước dữ liệu đã tính, quét 10% tiếp theo, v.v. Đối với các bảng quá lớn so với bộ đệm, bạn có thể tiết kiệm được một lượng công việc đáng kể với phương pháp này bằng cách thoát sớm.
  3. Đối với một số bảng, bạn có thể đủ may mắn để có các chỉ mục bao trùm trên tất cả các cột động. Tùy thuộc vào kích thước hàng hoặc các yếu tố khác, việc quét từng chỉ mục tại một thời điểm có thể nhanh hơn so với thực hiện quét bảng. Bạn cũng có thể thoát quá trình này sớm nếu kích thước bảng quá lớn sau khi đọc chỉ mục trên một cột.
  4. Độ dài trung bình của các cột động của bạn có thể không thay đổi nhiều theo thời gian. Có thể là thực tế để tiết kiệm độ dài trung bình mà bạn tính toán và sử dụng các giá trị đó trong tính toán của bạn trong một thời gian. Bạn có thể đặt lại các giá trị này dựa trên hoạt động DML trong các bảng hoặc dựa trên một số số liệu khác.
  5. Nếu có thể chạy thử nghiệm trên tất cả các bảng để phát triển thuật toán thì bạn có thể tận dụng các mẫu trong dữ liệu. Ví dụ: nếu bạn xử lý các bảng bắt đầu bằng số nhỏ nhất trước tiên, bạn có thể thấy rằng một khi bạn xử lý các bảng 10 (tôi đã tạo số này) trong một hàng quá lớn cho bộ đệm thì rất khó có bảng nào lớn hơn phù hợp với bộ nhớ cache. Điều này có thể được chấp nhận nếu loại trừ một vài bảng có thể phù hợp với bộ đệm.

Tôi nhận ra rằng tôi đã không bao gồm bất kỳ mã SQL nào trong câu trả lời này. Hãy cho tôi biết nếu nó hữu ích để viết mã demo cho bất kỳ ý tưởng nào mà tôi đã thảo luận ở đây.


2
Tôi đã không nghĩ đến cách tiếp cận loại trừ các bảng như thế, tôi thích cách tiếp cận
Tom V - thử topanswers.xyz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.