В Dynamics AX существует механизм кэширования, в котором таблицы можно настроить для загрузки в память и кэширования. Этот кэш ограничен определенным объемом в КБ для предотвращения проблем с памятью. Настройка, о которой я говорю, вызывается entiretablecache
и загружает всю таблицу в память, как только запрашивается одна запись.
До недавнего времени мы использовали некоторые сценарии, чтобы проверить размер таблиц с этим параметром, чтобы увидеть, превышает ли размер таблицы этот предел.
Однако теперь сжатие вступает в игру, и такие вещи, как sp_spaceused или sys.allocation_units, по- видимому, сообщают пространство, фактически используемое сжатыми данными.
Очевидно, что сервер приложений работает с несжатыми данными, поэтому размер данных на диске в SQL Server не имеет значения. Мне нужен реальный размер несжатых данных.
Я знаю о sp_estimate_data_compression_savings, но, как следует из названия, это только оценка.
Я бы предпочел, чтобы размер был максимально правильным.
Единственный способ, которым я мог придумать, - это какой-то сложный динамический SQL, создающий несжатые таблицы с той же структурой, что и сжатые таблицы, вставляя сжатые данные в эту теневую таблицу и затем проверяя размер этой теневой таблицы.
Излишне говорить, что это немного утомительно и требует времени для работы с базой данных в несколько сотен ГБ.
Powershell мог бы быть вариантом, но я не хотел бы перебирать все таблицы, чтобы выполнить select *
над ними проверку размера в сценарии, так как это просто заполнило бы кэш и, вероятно, заняло бы много времени.
Короче говоря, мне нужен способ получить размер для каждой таблицы, поскольку она будет однажды распакована и с фрагментацией из уравнения, представленного приложению, если это возможно. Я открыт для разных подходов, T-SQL предпочтительнее, но я не против Powershell или других творческих подходов.
Предположим, что буфер в приложении - это размер данных. Bigint всегда имеет размер bigint, а символьный тип данных составляет 2 байта на символ (юникод). BLOB-данные также принимают размер данных, перечисление в основном представляет собой int, а числовые данные - числовые (38,12), datetime - это размер datetime. Также нет никаких NULL
значений, они либо хранятся как пустая строка, 1900-01-01
либо как ноль.
Нет документации о том, как это реализовано, но предположения основаны на некотором тестировании и сценариях, используемых PFE и группой поддержки (которые, очевидно, также игнорируют сжатие, поскольку проверка встроена в приложение, и приложение не может сказать, если базовые данные сжаты), который также проверяет размеры таблицы. Эта ссылка, например, гласит:
Избегайте использования кешей для полной таблицы в формате FullTable (в AX 2009 более 128 КБ или 16 страниц, в AX 2012 в настройках приложения «размер кэша всей таблицы» [по умолчанию: 32 КБ или 4 страницы]) - вместо этого перейдите к записи кэширования.
источник
Ответы:
Хотя стремление к этой информации, безусловно, понятно, получение этой информации, особенно в контексте «как можно более точного», сложнее, чем все ожидают из-за ошибочных предположений. Делаете ли вы идею несжатой теневой таблицы, упомянутую в вопросе, или предложение @ sp_BlitzErik в комментарии о восстановлении БД и распаковке там для проверки, не следует предполагать, что размер несжатой таблицы == размер указанных данных в памяти на сервере приложений:
Есть все строки в таблице в кэше? Или просто в пределах диапазона? Здесь предполагается, что это все, и это может быть правильно, но я полагал, что по крайней мере следует упомянуть, что это может быть не так (если в документации не указано иное, но в любом случае это второстепенный вопрос, просто не хотелось это не говоря уже).
Вопрос был обновлен до состояния: да, все строки кэшируются.
Структура накладных
страница и накладные расходы на стороне БД: сколько строк помещается на странице, определяется многими факторами, которые могут отбросить оценки. Даже при значении
FILLFACTOR
100 (или 0) на странице все еще остается неиспользованное пространство, так как его недостаточно для всей строки. И это в дополнение к заголовку страницы. Кроме того, если активирована какая-либо функция изоляции моментальных снимков, я полагаю, что будет дополнительно 13 байт на строку, занятую номером версии, и это приведет к сбою оценок. Существуют и другие мелочи, связанные с фактическим размером строки (растровое изображение NULL, столбцы переменной длины и т. Д.), Но упомянутые до сих пор элементы сами по себе должны иметь значение.какой тип коллекции используется для хранения кэшированных результатов? Я предполагаю, что это приложение .NET, так это
DataTable
? Общий список? SortedDictionary? Каждый тип коллекции имеет различное количество подслушанных. Я не ожидал бы, что какой-либо из вариантов обязательно отразит накладные расходы Page и Row на стороне БД, особенно в масштабе (я уверен, что небольшое количество строк может не иметь достаточно различных значений, но вы не ищете различий в сотнях байтов или просто несколько кБ).CHAR
/VARCHAR
данные хранятся по 1 байту на символ (на данный момент игнорируются двухбайтовые символы).XML
оптимизирован, чтобы не занимать почти столько же места, сколько подразумевает текстовое представление. Этот тип данных создает словарь имен элементов и атрибутов и заменяет фактические ссылки на них в документе их соответствующими идентификаторами (на самом деле, довольно приятно). В противном случае строковыми значениями являются все UTF-16 (2 или 4 байта на «символ»), как иNCHAR
/NVARCHAR
.DATETIME2
находится между 6 и 8 байтами.DECIMAL
между 5 и 17 байтами (в зависимости от точности).строки (опять-таки, при условии .NET) всегда имеют формат UTF-16. Нет никакой оптимизации для 8-битных строк, таких как то, что
VARCHAR
имеет место. НО, строки также могут быть «интернированы», что является общей копией, на которую можно ссылаться много раз (но я не знаю, работает ли это для строк в коллекциях, или если так, если это работает для всех типов коллекций).XML
может храниться или не храниться в памяти одним и тем же способом (я должен это посмотреть).DateTime
всегда 8 байт (например , T-SQLDATETIME
, но не так, какDATE
,TIME
илиDATETIME2
).Decimal
это всегда 16 байт .Все это говорит о том, что на стороне БД вы почти ничего не можете сделать, чтобы получить даже достаточно точный объем памяти на стороне сервера приложений. Вам нужно найти способ опросить сам сервер приложений, после загрузки определенной таблицы, поэтому знайте, насколько он велик. И я не уверен, что отладчик позволит вам увидеть размер во время выполнения заполненной коллекции. Если нет, то единственный способ приблизиться - это пройти по всем строкам таблицы, умножив каждый столбец на соответствующий размер .NET (например,
INT
=* 4
,VARCHAR
=DATALENGTH() * 2
,NVARCHAR
=DATALENGTH()
,XML
= 🙃 и т. Д.), Но это все еще оставляет вопрос накладных расходов коллекции плюс каждый элемент коллекции.Учитывая какое-то новое определение в вопросе, можно, вероятно, сделать следующий запрос, чтобы получить довольно близко. И не имеет значения, сжимается ли таблица или нет, хотя каждый человек должен определить, подходит ли сканирование всех строк в производственной среде (возможно, из восстановления или в непиковые часы):
Но помните, это не учитывает накладные расходы на коллекцию или элемент коллекции. И не уверен, сможем ли мы получить это значение без отладчика (или, возможно, что-то вроде ILSpy, но я не рекомендую этого, поскольку это может нарушать лицензионное соглашение в зависимости от местных законов).
источник
Из вашего вопроса кажется, что у вас максимальный размер кэша,
S
и вы не хотите загружать таблицы в кеш, которые превышают этот размер. Если это правда, то вам не нужно знать точный размер каждой таблицы. Вам просто нужно знать, является ли таблица больше или меньше максимального размера кэшаS
. Это значительно проще, в зависимости от определений столбцов и количества строк в ваших таблицах.Я согласен с замечательным ответом Соломона Руцкого, заключающимся в том, что анализ несжатых данных - это не тот путь, и может быть сложно найти хорошее приближение к истинному размеру таблицы в кеше. Однако я собираюсь поработать в рамках этого вопроса и предположить, что вы можете разработать формулу, которая достаточно близка на основе определений столбцов для статических типов данных и фактической длины ваших динамических столбцов.
Если у вас есть такое отображение типов данных на размер кэша, вы сможете оценить некоторые таблицы, даже не глядя на данные в них:
sys.partitions
и рассчитав размер таблицы, используя определения столбцов.BIGINT
столбцами может иметь размер этих данных, равный 10000000 * (8 + 8 + 8 + 8 + 8) = 400 Мбайт, что может быть больше вашего размера кэшаS
. Неважно, есть ли у него также куча строковых столбцов.BIGINT
столбцом иNVARCHAR(20)
столбцом может не превышать 100 * (8 + 2 * 20) = 4800 байт.S
, чем тот, который вряд ли поместится в кэш. Вам нужно провести тестирование, чтобы выяснить, существует ли такое значение.Возможно, вам придется запросить данные таблиц, которые не соответствуют ни одному из вышеуказанных критериев. Есть несколько приемов, которые вы можете использовать, чтобы минимизировать влияние на производительность. Я бы сказал, что у вас есть два конкурирующих приоритета: вы цените точность, но также не хотите сканировать все данные в вашей базе данных. Может быть возможно добавить некоторый буфер к вашим вычислениям. Я не знаю, является ли более приемлемым исключить таблицу, которая немного меньше максимального размера кэша,
S
или включить таблицу, которая немного превышает максимальный размер кэша.Вот несколько идей по ускорению запросов, которые смотрят на данные таблиц:
TABLESAMPLE
размер выборки достаточно велик.SUM()
что выходит раньше, на основе значения этого агрегата. Я только видел эту работу дляROW_NUMBER()
. Но вы можете отсканировать первые 10% таблицы, сохранить расчетный размер данных, отсканировать следующие 10% и т. Д. Для таблиц, которые слишком велики для кэша, вы можете сэкономить значительный объем работы с этим подходом, выйдя рано.Я понимаю, что я не включил SQL-код в этот ответ. Дайте мне знать, было бы полезно написать демонстрационный код для любой из идей, которые я обсуждал здесь.
источник