Показаны сообщения с ярлыком Storage. Показать все сообщения
Показаны сообщения с ярлыком Storage. Показать все сообщения

13.1.26

Почему не стоит сжимать файлы данных

Автор: Paul Randal, Why you should not shrink your data files

Одна из моих самых больших «болевых точек» — это сжатие файлов данных. Хотя, когда я работал в Microsoft, я отвечал за код сжатия, я не писал его (так что не вините меня! :-)), и это никогда не считалось достаточно серьёзной проблемой для клиентов, чтобы её исправлять. Но мне действительно не нравится процесс сжатия файлов данных.

Важно, не путайте сжатие журнала транзакций со сжатием файлов данных. Сжатие журнала может быть необходимо, если ваш журнал вышел из-под контроля, или как часть процесса устранения чрезмерной фрагментации VLF (см. отличные посты Кимберли здесь и здесь). Однако сжатие журнала должно быть редкой операцией и не должно быть частью какого-либо регулярного обслуживания, которое вы выполняете.

В любом случае, я не говорю об использовании параметра TRUNCATEONLY — всё, что он делает, — это отсекает неиспользуемое пространство в конце файлов — это совершенно нормально. Я говорю о фактическом запуске алгоритма сжатия.

Примечание переводчика: статьи Пола и Кимберли были написаны в те времена, когда доминировали HDD. Сейчас это уже больше экзотика и основу составляют диски SSD. Такие диски значительно превосходят жёсткие диски по производительности и времени доступа, что снижает негативные последствия сжатия данных. Однако, если сжимать данные часто, это может заметно снизить число циклов перезаписи ячеек памяти, которое ограничено, и приблизить срок исчерпания ресурса диска. Это ещё один аргумент, почему не стоит этим злоупотреблять.

10.1.26

Заблуждения о выполнении DMV для баз данных с меньшими уровнями совместимости

Автор: Paul Randal, Misconceptions about running DMVs on databases with lower compatibility levels

У моего класса перерыв на обед — время для записи в блоге! Это интересный вопрос, который возникает периодически (буквально час назад на SQL Server Central) и не очень широко известен.

Существует заблуждение, что вы не можете выполнять динамические административные представления (DMV) в базах данных с уровнем совместимости 80 или ниже. Это не так.

6.1.26

Заблуждения относительно журнала и резервных копий журнала: как самому проверить

Автор: Paul Randal, Misconceptions around the log and log backups: how to convince yourself

До сих пор широко распространено заблуждение, что при корректной работе в моделях восстановления FULL или BULK_LOGGED полные или дифференциальные резервные копии могут усекать журнал. Нет. Это НИКОГДА не происходит. Это одна из причин, по которой я посвящаю целый доклад этой теме на конференции PASS в этом году — поведение журнала транзакций, по моему скромному мнению, является одной из самых неправильно понимаемых частей SQL Server.

5.1.26

Заблуждения относительно восстановления базы данных

Автор: Paul Randal, Misconceptions around database repair

На этой неделе на форумах и в Twitter было оживлённо: люди сталкиваются с множеством интересных проблем. Я заметил, что существует много заблуждений относительно запуска восстановления (repair), поэтому, чтобы завершить пятницу, я пройдусь по их списку для вас. Вот эти заблуждения, по поводу некоторых из которых мне приходилось спорить с людьми несколько раз и в конце концов прибегать к фразе «Слушайте, я писал код восстановления, мне жаль, но вы не правы», что я ненавижу делать:

4.1.26

Заблуждения относительно добавления столбцов в таблицу

Автор: Paul Randal, Misconceptions around adding columns to a table

Это короткое продолжение моей статьи «Заблуждения вокруг размера null bitmap».

Битовая карта NULL всегда присутствует в записи данных (т.е. в записях в куче или на конечном уровне кластерного индекса), за исключением случаев, когда в SQL Server 2008 и новее все столбцы определены как SPARSE, но она необязательна в записях индексов, если все столбцы в записях индексов не допускают значения NULL. Заблуждение связано с тем, что происходит при добавлении нового столбца в таблицу. Распространённое заблуждение заключается в том, что если у вас есть 8 столбцов в таблице (и, следовательно, 8 битов в битовой карте NULL), и вы добавляете девятый столбец, то SQL Server должен обновить каждую запись, чтобы все битовые карты NULL содержали 9 битов. (Такое же заблуждение применяется к добавлению 17-го, 25-го, 33-го и т.д. столбцов).

3.1.26

Заблуждения относительно хранилища FILESTREAM

Автор: Paul Randal, Misconceptions around FILESTREAM storage

Эта короткая статья вызвана вопросом, поступившим через Twitter, (перефразированный) вопрос звучит так: «Могут ли данные FILESTREAM храниться удалённо?». Это сбивало с толку многих, и ни документация BOL по FILESTREAM, ни мой технический документ по FILESTREAM (см. здесь) прямо не отвечают на этот вопрос.

2.1.26

Заблуждения относительно повреждений: могут ли они исчезать?

Автор: Paul Randal, Misconceptions around corruptions: can they disappear?

Этот вопрос возникал уже несколько раз, совсем недавно — сегодня утром в письме: последующие запуски DBCC CHECKDB показывают разное количество повреждений, а иногда и вовсе их не находят — что происходит? Ещё более странно: задание обслуживания запускает DBCC CHECKDB, который показывает ошибки, но затем утром — никаких ошибок согласованности. Как?

29.12.25

Заблуждения о перестроении индексов (распределение, режим BULK_LOGGED, блокировки)

Автор: Paul Randal, Search Engine Q&A #19: Misconceptions around index rebuilds (allocation, BULK_LOGGED mode, locking)

Я обнаружил (и помог исправить) довольно много мифов и заблуждений об операциях перестроения индексов. Их достаточно, чтобы стоило написать об этом статью в блоге (да и здесь, в Орландо, слишком жарко, чтобы идти сидеть у бассейна, так что мы оба сидим здесь и пишем в блогах)…

26.12.25

Любопытный случай… немедленной записи и минимально логируемых операций

Автор: Paul Randal, The Curious Case of… eager writing and minimally-logged operations

У меня состоялось обсуждение по электронной почте с одним специалистом, который размышлял о резервных копиях журнала и минимально логируемых операциях. В частности, он был озадачен тем, как работает резервное копирование журнала, если после завершения операции контрольная точка не происходила. Ведь грязные страницы данных всё ещё остаются в памяти, верно?

Оказывается, это не так.

25.12.25

Любопытный случай… блокировки BULK_OPERATION при просмотре кучи (heap) с NOLOCK

Автор: Paul Randal, The Curious Case of… the BULK_OPERATION lock during a heap NOLOCK scan

Мне пришёл вопрос по электронной почте: один специалист заметил, что во время выполнения просмотра кучи с использованием NOLOCK на всю продолжительность операции на куче удерживалась блокировка BULK_OPERATION. Вопрос заключался в том, зачем нужна эта блокировка, ведь просмотр с NOLOCK, казалось бы, не должно читать проблемные страницы?

Ответ заключается в том, что эта дополнительная блокировка нужна именно потому, что сканирование с NOLOCK может прочитать проблемную страницу, если в тот же момент над кучей выполняется операция массовой загрузки (bulk operation).

24.12.25

Небольшая ошибка в столбце sample_ms в sys.dm_io_virtual_file_stats

Автор: Paul Randal, Small bug with sample_ms in sys.dm_io_virtual_file_stats

Мне написал бывший студент по поводу странного поведения столбца sample_ms в представлении sys.dm_io_virtual_file_stats. Предполагается, что он должен содержать количество миллисекунд, прошедших с момента запуска экземпляра SQL Server. У него есть экземпляр SQL Server 2016, работающий с августа 2019 года, и там отображается следующее:

  • ms_ticks из sys.dm_os_sys_info: 51915112684 (что соответствует 28 августа 2019 года)
  • sample_ms из sys.dm_io_virtual_file_stats: 375504432 (что составляет около 4,5 дней)

Очевидно, что внутренняя переменная в SQL Server несколько раз переполнилась или сбросилась, вероятно, при достижении 2^31 или 2^32, хотя начиная с SQL Server 2016 тип данных sample_ms должен быть bigint.

23.12.25

Любопытный случай… неубиваемого потока

Автор: Paul Randal, The Curious Case of… the un-killable thread

На прошлой неделе, преподавая курс IEPTO2, я объяснял, почему иногда поток невозможно завершить с помощью команды KILL, и подумал, что это отличная тема для статьи.

22.12.25

Любопытный случай… с object ID 99

Автор: Paul Randal, The Curious Case of… object ID 99

Сегодня я отвечал на вопрос под тегом #sqlhelp в Twitter и упомянул об использовании значения object ID 99, потому что SQL Server никогда не присвоит таблице идентификатор объекта 99. И я подумал, что это станет хорошей темой для небольшой записи в блоге.

21.12.25

Любопытный случай… журнал, генерируемый при выполнении DROP TABLE

Автор: Paul Randal, The Curious Case of… log generated during a DROP TABLE

На прошлой неделе я несколько раз обсуждал объём журнала транзакций, который генерируется при выполнении DROP TABLE для очень большой таблицы. В обоих случаях люди беспокоились об объёме журнала, и о том, не замедлит ли это работу.

Надеюсь, все вы знаете, что мифом является утверждение, будто операции DROP TABLE и TRUNCATE TABLE не журналируются. Если вы этого не знали, прочитайте мою запись в блоге на sqlperformance.com, где объясняется механизм отложенного удаления (deferred drop). Обе операции полностью журналируются и будут генерировать довольно много записей журнала транзакций.

Основная часть генерируемого журнала возникает из-за необходимости фиксировать в журнале освобождение экстентов и страниц внутри них. Для каждого экстента должен быть сброшен бит на соответствующей странице GAM и странице IAM, а все 8 страниц в экстенте должны быть помечены как освобождённые на соответствующей странице PFS (путем выключения бита 0x40 в каждом байте PFS). Таким образом, получается три записи журнала на каждый распределённый экстент.

Я быстро подготовил тестовый пример, чтобы показать вам записи журнала:

SELECT
[Current LSN],
[Operation],
[Context],
[Log Record Length],
[Description]
FROM fn_dblog (null, null);
Current LSN             Operation       Context  Length  Description
----------------------  --------------  -------- ------- ------------------------------------------------------
.
.
000001eb:00000010:016a  LOP_SET_BITS    LCX_IAM  72
000001eb:00000010:016b  LOP_MODIFY_ROW  LCX_PFS  88      Deallocated 0001:000026f0;Deallocated 0001:000026f1;Deallocated 0001:000026f2;Deallocated 0001:000026f3;Deallocated 0001:000026f4;Deallocated 0001:000026f5;Deallocated 0001:000026f6;Deallocated 0001:000026f7
000001eb:00000010:016c  LOP_SET_BITS    LCX_GAM  72      Deallocated 1 extent(s) starting at page 0001:000026f0
.
.

И этот набор из трёх записей журнала повторяется для каждого освобождаемого экстента.

Одно из обсуждений касалось удаления таблицы размером 20 ТБ. 

20 ТБ = 20 * 1024 * 1024 *1024 * 1024 = 21 990 232 555 520 байт. 

Один экстент — это 65 536 байт, поэтому 20 ТБ — это 21 990 232 555 520 / 65 536 = 335 544 320 экстентов. При 72 + 88 + 72 = 232 записываемых байта на экстент это означает, что удаление таблицы размером 20 ТБ приведёт к генерации как минимум 335 544 320 * 232 = 77 846 282 240 байт = 72,5 ГБ журнала транзакций, или примерно 0,35% от размера таблицы. Периодически генерируется небольшое количество других записей журнала, поэтому для надёжности я бы сказал, что это 0,35–0,4%.

Всё это не генерируется как одна транзакция (весь смысл отложенного удаления заключается в выполнении операции в фоновом режиме множеством небольших транзакций) и не генерируется мгновенно (поскольку фоновая задача отложенного удаления выполняется в одном потоке), поэтому эти записи журнала будут перемешаны со всем остальным, что происходит в базе данных, и отправлены на синхронную реплику AG так же, как и другие транзакции. Так что, хотя и генерируется дополнительный объём журнала, я не ожидаю, что это вызовет серьёзные проблемы.

И, конечно же, если эта таблица секционирована, вы можете выполнять операцию меньшими шагами, многократно переключая секции и удаляя их по одной.

Суть в том: выполнение DROP или TRUNCATE для таблицы требует генерации в журнале примерно 0,35–0,4% от размера таблицы.



20.12.25

Любопытный случай… карты прерванных XDES

Автор: Paul Randal, The Curious Case of… the aborted xdes map

На прошлой неделе мне по электронной почте задали вопрос о странных сообщениях в журнале ошибок, похожих на эти:

[DbId:12]. Removing xdes id: 0000:8112c9d0 from aborted xdes map.
[DbId:12]. Removing xdes id: 0000:8112b45e from aborted xdes map.
[DbId:12]. Removing xdes id: 0000:8112b403 from aborted xdes map.

Прежде всего, XDES — это структура данных (и класс C++) в механизме хранения (Storage Engine), представляющий транзакцию; это сокращение от «transaction descriptor» (дескриптор транзакции). Идентификатор XDES — это тот же самый идентификатор, который вы видите в столбце Transaction ID в выводе функции fn_dblog для изучения содержимого журнала транзакций (см. примеры здесь).

Эти сообщения безвредны и связаны с внутренней работой функции Ускоренного восстановления баз данных (Accelerated Database Recovery, ADR), которая позволяет мгновенно откатывать транзакции с помощью умного механизма версионности.

19.12.25

Любопытный случай… ограничения размера строки в 8060 байт

Автор: Paul Randal, The Curious Case of… the 8060-byte row size limit

На прошлой неделе мне задали вопрос о том, почему существует ограничение в 8060 байт на размер строки и почему страницы файлов данных иногда показывают более 8060 байт свободного места при просмотре с помощью DBCC PAGE.

Прежде чем объяснять, позвольте мне прояснить, что ограничение в 8060 байт касается только той части записи, которая хранится на странице данных или индекса в единице распределения «внутристроковых данных» (in-row data). Запись может иметь множество столбцов LOB, которые хранятся вне строки в единице распределения «данных LOB» (например, столбцы varchar(max) или FILESTREAM), и/или не-LOB столбцов переменной длины, которые были вытеснены из строки для хранения в единице распределения «переполнения строки» (например, столбцы char(1-8000), nchar(1-4000) или sqlvariant). Таким образом, фактический размер строки практически не ограничен.

Я мог бы перефразировать исходный вопрос так: учитывая, что размер страницы составляет 8192 байта, и только 96 байт используется для заголовка страницы, почему размер внутристроковой записи ограничен 8060 байтами? Куда деваются остальные 36 байт доступного пространства?

18.12.25

Любопытный случай… восстановления таблицы в другую базу данных

Автор: Paul Randal, The Curious Case of… restoring a table into a different database

(«Любопытный случай…» раньше был частью нашей двухнедельной рассылки, но мы решили сделать его обычной записью в блоге, чтобы он мог выходить иногда чаще. Он рассказывает о чём-то интересном, с чем столкнулся один из нас при работе с клиентом, проведении тестов или в случайном вопросе от сообщества.)

В одном списке рассылки, на который я подписан, сегодня кто-то поинтересовался возможностью реализации восстановления таблицы в другую базу данных, в которой уже есть свои данные. Это интересное умственное упражнение, поэтому я написал ответ для списка, а потом подумал, что из него получится хорошая запись в блоге.

Восстановление таблицы в другую базу данных, где уже есть данные, на самом деле гораздо сложнее, чем может показаться.

17.12.25

Ленивое усечение журнала, или почему VLF могут оставаться со статусом 2 после очистки журнала

Автор: Paul Randal, Lazy log truncation or why VLFs might stay at status 2 after log clearing

Ранее мне прислали интересный вопрос о том, почему человек видит множество VLF (виртуальных файлов журнала) в журнале со статусом = 2 (что означает «активный») после очистки (также известной как «усечение») журнала, при том что log_reuse_wait_desc показывает NOTHING.

Я немного покопался и всё, что смог найти, — это старая запись в блоге от 2013 года, которая демонстрирует это поведение и упоминает, что оно происходит при зеркальном отображении и в группах доступности. Я не слышал об этом поведении раньше, но предположил причину и подтвердил её с командой SQL Server.

16.12.25

Новое значение статуса VLF

Автор: Paul Randal, New VLF status value

По крайней мере с тех пор, как я начал работать в команде SQL Server (сразу после выхода версии 7.0) и до недавнего времени, существовало всего два кода статуса VLF (виртуального файла журнала):

  • 0 = VLF не активен (т.е. его можно (повторно) активировать и перезаписать)
  • 1 = не используется, и, кажется, никто не помнит, что это раньше означало
  • 2 = VLF активен, потому что хотя бы одна запись журнала в нём «требуется» SQL Server по какой-либо причине (например, ещё не была включена в резервную копию журнала или не просканирована репликацией)

Несколько недель назад я узнал о новом коде статуса VLF, который был добавлен ещё в SQL Server 2012, но не был широко известен до недавнего времени (по крайней мере, я никогда с ним не сталкивался в реальных условиях). Я провёл несколько обсуждений с другом из Microsoft (Шоном Галларди, PFE и MCM из Тампа), которому удалось покопаться в коде, чтобы выяснить, когда он используется.

14.12.25

Read committed не гарантирует многого…

Автор: Paul Randal, Read committed doesn’t guarantee much…

Некоторое время назад я участвовал в переписке по электронной почте, где люди обсуждали некоторое «странное» поведение SQL Server. Проблема возникала в SQL Server 2016 при использовании уровня изоляции по умолчанию — read committed. Сценарий был следующим:

  1. Создать таблицу с несколькими столбцами
  2. Пакет 1: В одном окне SSMS выполнить следующее (что занимает 10 секунд):
    • Начать транзакцию
    • Вставить 1000 строк в таблицу с задержкой WAITFOR DELAY 0.01 секунды между каждой вставкой
    • Зафиксировать транзакцию
  3. Пакет 2: Во втором окне SSMS:
    • Выполнить SELECT * из таблицы

«Странное» поведение заключается в том, что когда выборка «Пакета 2» завершается после того, как была заблокирована транзакцией «Пакета 1», она возвращает не все 1000 строк (даже несмотря на то, что «Пакет 1» завершился). Более того, в зависимости от того, когда была запущена выборка «Пакета 2» в течение 10 секунд выполнения «Пакета 1», «Пакет 2» возвращает разное количество строк. Такое поведение также сообщалось и в более ранних версиях SQL Server. Это легко воспроизвести в SQL Server 2016/2017 и можно воспроизвести во всех более ранних версиях с одним изменением конфигурации (подробнее чуть позже).