В тази статия разглеждам размера на съхранение на ввремета тип данни в SQL Server.
По-специално гледам на следното:
- Документацията на Microsoft
- Данни, съхранявани в променлива
- Дължина в байтове с помощта на
DATALENGTH()
- Дължина в байтове с помощта на
DATALENGTH()
след конвертиране в varbinary
- Дължина в байтове с помощта на
- Данни, съхранявани в база данни
- Дължина в байтове с помощта на
COL_LENGTH()
- Дължина в байтове с помощта на
DBCC PAGE()
- Дължина в байтове с помощта на
Документацията на Microsoft
Официалната документация на Microsoft за времета Типът данни показва, че неговият размер за съхранение е между 3 и 5 байта, в зависимост от използваната прецизност.
Този тип данни позволява дефинирана от потребителя точност. Можете да използвате време(n) за да посочите точността, където n е скала между 0 и 7.
Ето данните, които Microsoft представя завреме тип данни:
Посочен мащаб | Резултат (прецизност, мащаб) | Дължина на колоната (байтове) | Дробни секунди точност |
---|---|---|---|
време | (16,7) | 5 | 7 |
време(0) | (8,0) | 3 | 0-2 |
време(1) | (10,1) | 3 | 0-2 |
време(2) | (11,2) | 3 | 0-2 |
време(3) | (12,3) | 4 | 3-4 |
време(4) | (13,4) | 4 | 3-4 |
време(5) | (14,5) | 5 | 5-7 |
време(6) | (15,6) | 5 | 5-7 |
време(7) | (16,7) | 5 | 5-7 |
За целите на тази статия се интересувам основно от Дължината на колоната (байтове) колона. Това ни казва колко байта се използват за съхраняване на този тип данни в база данни.
От гледна точка на потребителя, времето типът данни работи по същия начин като частта от времето на datetime2 . Той има дефинирана от потребителя точност за частични секунди и приема скала от 0 до 7.
Останалата част от тази статия преминава през различни примери, където връщам размера на съхранение на време стойности в различни контексти.
Данни, съхранявани в променлива
Първо, ще запазя време стойност в променлива и проверете нейния размер за съхранение. След това ще преобразувам тази стойност в varbinary и го проверете отново.
Дължина в байтове с използване на DATALENGTH
Ето какво се случва, ако използваме DATALENGTH()
функция за връщане на броя байтове, използвани за време(7) стойност:
DECLARE @t time(7);SET @t ='10:15:30.1234567';ИЗБЕРЕТЕ @t КАТО 'Стойност', DATALENGTH(@t) КАТО 'Дължина в байтове';
Резултат
+------------------+------------------+| Стойност | Дължина в байтове ||-----------------+-------------------|| 10:15:30.1234567 | 5 |+------------------+------------------+
Стойността в този пример има максимална скала от 7 (защото декларирам променливата като time(7) ) и връща дължина от 5 байта.
Това може да се очаква, тъй като съответства на размера за съхранение, посочен в таблицата на Microsoft.
Ако обаче преобразуваме стойността в varbinary получаваме различен резултат.
Дължина в байтове след преобразуване във „варбиниран“
Някои разработчици обичат да преобразуват време или дата и час2 променливи към varbinary защото е по-представителен за това как SQL Server го съхранява в базата данни. Въпреки че това е частично вярно, резултатите не са точно същите като съхранената стойност (повече за това по-долу).
Ето какво се случва, ако преобразуваме нашето време стойност до варбинарна :
DECLARE @t time(7);SET @t ='10:15:30.1234567';SELECT CONVERT(VARBINARY(16), @t) КАТО 'Стойност', DATALENGTH(CONVERT(VARBINARY(16), @t) )) КАТО 'Дължина в байтове';
Резултат
+----------------+------------------+| Стойност | Дължина в байтове ||----------------+-------------------|| 0x0787A311FC55 | 6 |+----------------+------------------+
В този случай получаваме 6 байта. Нашата стойност вече използва 1 байт повече от това, което е посочено в документацията.
Това е така, защото се нуждае от допълнителен байт, за да съхрани прецизността.
Това е шестнадесетично представяне на времето стойност. Действителната стойност на времето (и нейната прецизност) е всичко след 0x
. Всяка двойка шестнадесетични знаци е байт. Има 6 двойки и следователно 6 байта. Това се потвърждава, когато използваме DATALENGTH()
за да върнете дължината в байтове.
В този пример можем да видим, че първият байт е 07
. Това представлява прецизността (използвах скала от 7 и това е, което се показва тук).
Ако променя мащаба, можем да видим, че първият байт се променя, за да съответства на мащаба:
DECLARE @t time(3);SET @t ='10:15:30.1234567';SELECT CONVERT(VARBINARY(16), @t) КАТО 'Стойност', DATALENGTH(CONVERT(VARBINARY(16), @t) )) КАТО 'Дължина в байтове';
Резултат
<пред>+--------------+-------------------+| Стойност | Дължина в байтове ||--------------+-------------------|| 0x034B823302 | 5 |+--------------+-------------------+Можем също да видим, че дължината е съответно намалена. Но отново, това е един байт повече от това, което документацията казва, че трябва да използва.
Въпреки че документацията на Microsoft за време не споменава изрично това, документацията за datetime2 посочва следното:
Първият байт на datetime2 value съхранява прецизността на стойността, което означава действителното съхранение, необходимо за datetime2 стойността е размерът на паметта, посочен в таблицата по-горе, плюс 1 допълнителен байт за съхраняване на точността. Това прави максималния размер на datetime2 стойност 9 байта – 1 байт съхранява прецизност плюс 8 байта за съхранение на данни с максимална точност.
И datetime2 типът данни работи по абсолютно същия начин по отношение на горните примери. С други думи, той отчита допълнителния байт само когато е преобразуван в варбиниран .
Така че допълнителният байт, споменат в документацията на Microsoft, изглежда се отнася и за време .
Въпреки това, действителният размер за съхранение на вашето време стойностите ще посочат къде се съхраняват данните.
Данни, съхранявани в база данни
Когато колона от база данни има тип време , точността му е посочена на ниво колона – не на ниво данни. С други думи, посочва се веднъж за цялата колона. Това има смисъл, защото когато дефинирате колона като time(7) , знаете, че всички редове ще бъдат time(7) . Няма нужда да изразходвате ценни байтове, повтаряйки този факт на всеки ред.
Когато преглеждате вчас стойността, тъй като е съхранена в SQL Server, ще видите, че е същата като варбината резултат, но без прецизността.
По-долу са дадени примери, които показват как време стойностите се съхраняват в SQL Server.
В тези примери създавам база данни с различни време(n) колони и след това използвайте COL_LENGTH()
за да върне дължината на всяка колона в байтове. След това вмъквам стойности в тези колони, преди да използвам DBCC PAGE
за да проверявате размера на съхранение, който всекипът стойността заема файла на страницата.
Създайте база данни:
СЪЗДАВАНЕ НА БАЗА ДАННИ Тест;
Създайте таблица:
ИЗПОЛЗВАЙТЕ Тест;СЪЗРАЙТЕ ТАБЛИЦА TimeTest ( t0 време(0), t1 време(1), t2 време(2), t3 време(3), t4 време(4), t5 време(5), t6 време(6) ), t7 време(7) );
В този случай създавам осем колони – по една за всяка дефинирана от потребителя скала, която можем да използваме с време(n) .
Сега можем да проверим размера на съхранение на всяка колона.
Дължина в байтове с помощта на COL_LENGTH()
Използвайте COL_LENGTH()
за да проверите дължината (в байтове) на всяка колона:
ИЗБЕРЕТЕ COL_LENGTH ('TimeTest', 't0') КАТО 't0', COL_LENGTH ('TimeTest', 't1') КАТО 't1', COL_LENGTH ('TimeTest', 't2') КАТО 't2', COL_LENG ( 'TimeTest' , 't3' ) КАТО 't3', COL_LENGTH ( 'TimeTest', 't4') КАТО 't4', COL_LENGTH ( 'TimeTest', 't5') КАТО 't5', COL_LENGTH ( 'TimeTest', 't6' ) КАТО 't6', COL_LENGTH ( 'TimeTest' , 't7' ) КАТО 't7';
Резултат:
+------+------+------+------+------+-----+---- --+------+| t0 | t1 | t2 | t3 | t4 | t5 | t6 | t7 ||------+------+------+------+------+------+----- -+------|| 3 | 3 | 3 | 4 | 4 | 5 | 5 | 5 |+------+------+------+------+------+------+----- -+------+
Така че още веднъж получаваме същия резултат, който документацията гласи, че ще получим. Това може да се очаква, тъй като в документацията изрично е посочено „Дължина на колоната (байтове)“, което е точно това, което измерваме тук.
Не забравяйте, че това е преди въвеждаме всякакви данни. Самите колони определят точността (и следователно размера на съхранение) на всички данни, които се вмъкват, а не обратното.
Използвайте DBCC PAGE, за да проверите съхранените данни
Сега нека вмъкнем данни, след което използваме DBCC PAGE
за да намерите действителния размер за съхранение на данните, които съхраняваме във всяка колона.
Вмъкване на данни:
ДЕКЛАРИРАЙТЕ @t time(7) ='10:15:30.1234567';ВМЕСЕТЕ В TimeTest ( t0, t1, t2, t3, t4, t5, t6, t7 )ИЗБЕРЕТЕ @t, @t, @t, @ t, @t, @t, @t, @t;
Сега изберете данните (само за да ги проверите):
ИЗБЕРЕТЕ * ОТ TimeTest;
Резултат (с помощта на вертикален изход):
<пред>t0 | 10:15:30t1 | 10:15:30.1000000t2 | 10:15:30.1200000t3 | 10:15:30.1230000t4 | 10:15:30.1235000t5 | 10:15:30.1234600t6 | 10:15:30.1234570t7 | 10:15:30.1234567Както се очаква, стойностите използват прецизността, която е била предварително посочена на ниво колона.
Имайте предвид, че моята система показва крайни нули. Вашият може или не може да го направи. Независимо от това, това не засяга действителната прецизност или точност.
Сега, преди да използваме DBCC PAGE()
, трябва да знаем кой PagePID да му предадем. Можем да използваме DBCC IND()
за да го намерите.
Намерете PagePID:
DBCC IND('Test', 'dbo.TimeTest', 0);
Резултат (с помощта на вертикален изход):
-[ ЗАПИС 1 ]------------------------------PageFID | 1PagePID | 308IAMFID | NULLIAMPID | NULLObjectID | 1541580530IndexID | 0Номер на дял | 1PartitionID | 72057594043236352iam_chain_type | В ред dataPageType | 10 Ниво на индекс | NULLNextPageFID | 0NextPagePID | 0PrevPageFID | 0PrevPagePID | 0-[ ЗАПИС 2 ]------------------------------PageFID | 1PagePID | 384IAMFID | 1IAMPID | 308ObjectID | 1541580530IndexID | 0Номер на дял | 1PartitionID | 72057594043236352iam_chain_type | В ред dataPageType | 1Ниво на индекс | 0Следваща страницаFID | 0NextPagePID | 0PrevPageFID | 0PrevPagePID | 0
Това връща два записа. Интересуваме се от PageType от 1 (2-ри запис). Искаме PagePID от този запис. В този случай PagePID е 384 .
Сега можем да вземем този PagePID и да го използваме в следното:
DBCC TRACEON(3604, -1);DBCC PAGE(Тест, 1, 384, 3);
В момента се интересуваме основно от следната част:
Слот 0 Колона 1 Отместване 0x4 Дължина 3 Дължина (физическа) 3t0 =10:15:30 Слот 0 Колона 2 Отместване 0x7 Дължина 3 Дължина (физическа) 3t1 =10:15:30 Дължина Colum Изкл. Слот 0x3 (физическа) 3t2 =10:15:30.12 Слот 0 Колона 4 Отместване 0xd Дължина 4 Дължина (физическа) 4t3 =10:15:30.123 Слот 0 Колона 5 Отместване 0x11 Дължина 4 Дължина 4 4 Дължина 4:5 Slot =4 Дължина 4:5 Slot Колона 6 Отместване 0x15 Дължина 5 Дължина (физическа) 5t5 =10:15:30.12346 Слот 0 Колона 7 Отместване 0x1a Дължина 5 Дължина (физическа) 5t6 =10:15:30 Дължина (физическа) 5t5 =10:15:30.12346 Слот 0 Колона 7 Отместване 0x1a Дължина 5 Дължина (физическа) 5t6 =10:15:30 Дължина 5.1234 Дължина 0.1234 10:15:30.1234567
Така получаваме същия резултат, както е посочено в документацията. Това би предполагало, че точността не се съхранява със стойностите.
Можем да потвърдим това, като проверим действителните данни.
Действителните стойности на времето се съхраняват в тази част на файла на страницата:
изхвърляне на памет @0x0000000423ADA060000000000000000000:10002400 42900095 A205D459 384B8233 02F31603 .. $. B .. • ¢ .ôy8kрени.. ..
Можем да извлечем действителните стойности на времето, като премахнем няколко неща. След като бъде премахнат, следното ще остане:
42900095 a205d459 384b8233 02f31603167ae51e dc00c1f6 34990887 a311fc55
Тези шестнадесетични цифри съдържат всички наши данни за времето, но не и точността . Те обаче са подредени в 4 байтови парчета, така че трябва да пренаредим интервалите, за да получим отделните стойности.
Ето крайния резултат. Поставих всяка стойност за дата/час на нов ред за по-добра четливост.
42900095a205d459384b823302f31603167ae51edc00c1f634990887a311fc55
Това са действителните шестнадесетични стойности (минус точността ), които бихме получили, ако преобразуваме времето стойност до варбинарна . Като това:
ИЗБЕРЕТЕ CONVERT(VARBINARY(16), t0) КАТО 't0', CONVERT(VARBINARY(16), t1) КАТО 't1', CONVERT(VARBINARY(16), t2) КАТО 't2', CONVERT(VARBINARY( 16), t3) КАТО 't3', CONVERT(VARBINARY(16), t4) КАТО 't4', CONVERT(VARBINARY(16), t5) КАТО 't5', CONVERT(VARBINARY(16), t6) КАТО 't6 ', CONVERT(VARBINARY(16), t7) КАТО 't7'ОТ TimeTest;
Резултат (с помощта на вертикален изход):
<пред>t0 | 0x00429000t1 | 0x0195A205t2 | 0x02D45938t3 | 0x034B823302t4 | 0x04F3160316t5 | 0x057AE51EDC00t6 | 0x06C1F6349908t7 | 0x0787A311FC55Тази заявка дава същия резултат – с изключение на това, че всяка стойност е била добавена с прецизност.
Ето таблица, която сравнява действителните данни от файла на страницата с резултатите от CONVERT()
операция.
Данни за файл на страницата | CONVERT() Данни |
---|---|
429 000 | 00429000 |
95a205 | 0195A205 |
d45938 | 02D45938 |
4b823302 | 034B823302 |
f3160316 | 04F3160316 |
7ae51edc00 | 057AE51EDC00 |
c1f6349908 | 06C1F6349908 |
87a311fc55 | 0787A311FC55 |
Така че можем да видим, че файлът на страницата не съхранява точността, но конвертираният резултат го прави.
Осветих действителните части за дата и час в червено. Премахнах и 0x
префикс от преобразуваните резултати, така че да се показват само действителните данни за дата/час (заедно с точността).
Също така имайте предвид, че шестнадесетичният знак не е чувствителен към главни букви, така че фактът, че единият използва малки букви, а другият използва главни букви, не е проблем.
Заключение
При преобразуване на време стойност до варбинарна , се нуждае от допълнителен байт за съхраняване на точността. Той се нуждае от прецизност, за да интерпретира частта от време (тъй като това се съхранява като интервал от време, чиято точна стойност ще зависи от точността).
Когато се съхранява в база данни, точността се посочва веднъж на ниво колона. Това изглежда логично, тъй като няма нужда да добавяте прецизност към всеки ред, когато всички редове така или иначе имат същата точност. Това ще изисква допълнителен байт за всеки ред, което би увеличило ненужно изискванията за съхранение.