| 6 | | * распределба на податоците во `filegroups` по временски период |
| 7 | | * партиционирање по датум (година/деценија) |
| 8 | | * clustered индекси поставени на `partition scheme` за да се активира `partitioning` |
| 9 | | |
| 10 | | == Filegroups по временски период |
| 11 | | |
| 12 | | Креирани се `filegroups` за логичка/физичка сегментација на податоците: |
| 13 | | |
| 14 | | * `FG_Old` (пред 2000) |
| 15 | | * `FG_2000s` (2000-2009) |
| 16 | | * `FG_2010s` (2010-2019) |
| 17 | | * `FG_2020s` (2020-2029) |
| 18 | | * `FG_Future` (2030+) |
| 19 | | |
| 20 | | Причина: |
| 21 | | * подобро управување со големи податочни сетови (VLDB пристап) |
| 22 | | * можност за backup/restore по filegroup |
| 23 | | * подобра I/O локалност и одржување (архивирање на стари партиции) |
| 24 | | |
| 25 | | {{{#!sql |
| 26 | | alter database HospitalSyntheaDB add filegroup FG_Old; |
| 27 | | go |
| 28 | | alter database HospitalSyntheaDB add file (name='FG_Old', filename='C:\Users\User\Documents\DBA\FG_Old.ndf') to filegroup FG_Old; |
| 29 | | go |
| 30 | | |
| 31 | | alter database HospitalSyntheaDB add filegroup FG_2000s; |
| 32 | | go |
| 33 | | alter database HospitalSyntheaDB add file (name='FG_2000s', filename='C:\Users\User\Documents\DBA\FG_2000s.ndf') to filegroup FG_2000s; |
| 34 | | go |
| 35 | | |
| 36 | | alter database HospitalSyntheaDB add filegroup FG_2010s; |
| 37 | | go |
| 38 | | alter database HospitalSyntheaDB add file (name='FG_2010s', filename='C:\Users\User\Documents\DBA\FG_2010s.ndf') to filegroup FG_2010s; |
| 39 | | go |
| 40 | | |
| 41 | | alter database HospitalSyntheaDB add filegroup FG_2020s; |
| 42 | | go |
| 43 | | alter database HospitalSyntheaDB add file (name='FG_2020s', filename='C:\Users\User\Documents\DBA\FG_2020s.ndf') to filegroup FG_2020s; |
| 44 | | go |
| 45 | | |
| 46 | | alter database HospitalSyntheaDB add filegroup FG_Future; |
| 47 | | go |
| 48 | | alter database HospitalSyntheaDB add file (name='FG_Future', filename='C:\Users\User\Documents\DBA\FG_Future.ndf') to filegroup FG_Future; |
| 49 | | go |
| 50 | | |
| 51 | | }}} |
| 52 | | |
| 53 | | == Партиционирање |
| 54 | | |
| 55 | | === Партициски функции и шема |
| 56 | | |
| 57 | | Поради тоа што `encounters`, `medications`, `observations` и `procedures` користат ист тип за колоната за датум - `datetime2`, тие може да користат иста функција - `pf_Encounters_Year` и иста партициска шема - `ps_Encounters_Year`. |
| 58 | | |
| 59 | | Табелата `conditions` користи различен тип за датум - `date`, па за неа ќе се направи посебна партициска функција и шема. |
| 60 | | |
| 61 | | ==== `pf_Encounters_Year` и `ps_Encounters_Year` |
| 62 | | |
| 63 | | Партициската функција - `pf_Encounters_Year (datetime2)` е креирана со `boundaries: 2000, 2010, 2020, 2030`. |
| 64 | | |
| 65 | | Партициската шема `ps_Encounters_Year` ги мапира партициите на горните `filegroups`. |
| 66 | | |
| 67 | | {{{#!sql |
| 68 | | create partition function pf_Encounters_Year (datetime2) |
| 69 | | as range right for values |
| 70 | | ( |
| 71 | | '2000-01-01', |
| 72 | | '2010-01-01', |
| 73 | | '2020-01-01', |
| 74 | | '2030-01-01' |
| 75 | | ); |
| 76 | | go |
| 77 | | |
| 78 | | create partition scheme ps_Encounters_Year |
| 79 | | as partition pf_Encounters_Year to |
| 80 | | ( |
| 81 | | FG_Old, |
| 82 | | FG_2000s, |
| 83 | | FG_2010s, |
| 84 | | FG_2020s, |
| 85 | | FG_Future |
| 86 | | ); |
| 87 | | go |
| 88 | | }}} |
| 89 | | |
| 90 | | * `range right` значи дека граничната вредност припаѓа на десната (повисока) партиција. |
| 91 | | |
| 92 | | ==== `pf_Conditions_Year` и `ps_Conditions_Year` |
| 93 | | |
| 94 | | {{{#!sql |
| 95 | | create partition function pf_Conditions_Year (date) |
| 96 | | as range right for values |
| 97 | | ( |
| 98 | | '2000-01-01', |
| 99 | | '2010-01-01', |
| 100 | | '2020-01-01', |
| 101 | | '2030-01-01' |
| 102 | | ); |
| 103 | | go |
| 104 | | |
| 105 | | create partition scheme ps_Conditions_Year |
| 106 | | as partition pf_Conditions_Year to |
| 107 | | ( |
| 108 | | FG_Old, |
| 109 | | FG_2000s, |
| 110 | | FG_2010s, |
| 111 | | FG_2020s, |
| 112 | | FG_Future |
| 113 | | ); |
| 114 | | go |
| 115 | | }}} |
| 116 | | |
| 117 | | === Clustered индекси со партиционирање |
| 118 | | |
| 119 | | Партиционирањето реално се применува кога clustered индексот е креиран врз партициската шема. |
| 120 | | |
| 121 | | Помалите табели како `allergies` и `immunizations` не се партиционирани затоа што се помали и не зависат од временски период. |
| 122 | | |
| 123 | | ==== `encounters` |
| 124 | | |
| 125 | | {{{#!sql |
| 126 | | create clustered index CI_Encounters_StartDate_Id |
| 127 | | on encounters(start, Id) |
| 128 | | with (drop_existing = off) |
| 129 | | on ps_Encounters_Year(start); |
| 130 | | go |
| 131 | | }}} |
| 132 | | |
| 133 | | ==== `observations` |
| 134 | | |
| 135 | | {{{#!sql |
| 136 | | create clustered index CI_Observations_Date_Patient |
| 137 | | on observations([date], patient) |
| 138 | | with (drop_existing = off) |
| 139 | | on ps_Encounters_Year([date]); |
| 140 | | go |
| 141 | | }}} |
| 142 | | |
| 143 | | ==== `medications` |
| 144 | | |
| 145 | | {{{#!sql |
| 146 | | create clustered index CI_Medications_Start |
| 147 | | on medications([start], patient) |
| 148 | | with (drop_existing = off) |
| 149 | | on ps_Encounters_Year([start]); |
| 150 | | go |
| 151 | | }}} |
| 152 | | |
| 153 | | ==== `procedures` |
| 154 | | |
| 155 | | {{{#!sql |
| 156 | | create clustered index CI_Procedures_Start |
| 157 | | on procedures([start], patient) |
| 158 | | with(drop_existing = off) |
| 159 | | on ps_Encounters_Year([start]); |
| 160 | | go |
| 161 | | }}} |
| 162 | | |
| 163 | | ==== `conditions` |
| 164 | | |
| 165 | | {{{#!sql |
| 166 | | create clustered index CI_Conditions_Start |
| 167 | | on conditions([start], patient) |
| 168 | | with (drop_existing = off) |
| 169 | | on ps_Conditions_Year([start]); |
| 170 | | go |
| 171 | | }}} |
| 172 | | |
| 173 | | === Верификација |
| 174 | | |
| 175 | | Проверката е слична за сите табели. |
| 176 | | |
| 177 | | Подолу е прикажан пример само за `encounters` табелата. |
| 178 | | |
| 179 | | ==== Проверка дека датотечните групи се креирани исправно |
| 180 | | |
| 181 | | {{{#!sql |
| 182 | | select |
| 183 | | fg.name as FilegroupName, |
| 184 | | df.name as LogicalFileName, |
| 185 | | df.type_desc as FileType, |
| 186 | | df.physical_name as PhysicalPath, |
| 187 | | df.size / 128.0 as SizeMB |
| 188 | | from sys.filegroups fg |
| 189 | | left join sys.database_files df ON fg.data_space_id = df.data_space_id |
| 190 | | order by fg.name; |
| 191 | | go |
| 192 | | }}} |
| 193 | | |
| 194 | | ==== Проверка дека партициската шема и функцијата работат исправно |
| 195 | | |
| 196 | | {{{#!sql |
| 197 | | select |
| 198 | | ps.name as PartitionScheme, |
| 199 | | pf.name as PartitionFunction, |
| 200 | | dds.destination_id as PartitionNumber, |
| 201 | | fg.name as FilegroupName, |
| 202 | | prv.value as UpperBoundaryValue |
| 203 | | from sys.partition_schemes ps |
| 204 | | join sys.partition_functions pf on ps.function_id = pf.function_id |
| 205 | | join sys.destination_data_spaces dds on ps.data_space_id = dds.partition_scheme_id |
| 206 | | join sys.filegroups fg on dds.data_space_id = fg.data_space_id |
| 207 | | left join sys.partition_range_values prv |
| 208 | | on pf.function_id = prv.function_id |
| 209 | | and dds.destination_id = case when pf.boundary_value_on_right = 1 then prv.boundary_id + 1 else prv.boundary_id end |
| 210 | | where ps.name = 'ps_Encounters_Year' |
| 211 | | order by dds.destination_id; |
| 212 | | go |
| 213 | | ----------------------------- |
| 214 | | select |
| 215 | | fg.name as FilegroupName, |
| 216 | | df.name as LogicalFileName, |
| 217 | | df.physical_name, |
| 218 | | df.size / 128.0 as SizeMB |
| 219 | | from sys.filegroups fg |
| 220 | | left join sys.database_files df on fg.data_space_id = df.data_space_id; |
| 221 | | go |
| 222 | | }}} |
| 223 | | |
| 224 | | ==== Дистрибуција по партиции |
| 225 | | |
| 226 | | {{{#!sql |
| 227 | | select |
| 228 | | $partition.pf_Encounters_Year([start]) as PartitionNumber, |
| 229 | | count(*) as 'RowCount', |
| 230 | | min([start]) as MinDate, |
| 231 | | max([start]) as MaxDate |
| 232 | | from dbo.encounters |
| 233 | | group by $partition.pf_Encounters_Year([start]) |
| 234 | | order by PartitionNumber; |
| 235 | | go |
| 236 | | }}} |
| 237 | | |
| 238 | | ==== Filegroup usage |
| 239 | | |
| 240 | | {{{#!sql |
| 241 | | select |
| 242 | | fg.name as FilegroupName, |
| 243 | | count(*) as PartitionCount |
| 244 | | from sys.partitions p |
| 245 | | join sys.indexes i on p.object_id = i.object_id and p.index_id = i.index_id |
| 246 | | join sys.data_spaces ds on i.data_space_id = ds.data_space_id |
| 247 | | join sys.filegroups fg on ds.data_space_id = fg.data_space_id |
| 248 | | where object_name(p.object_id) = 'Encounters' |
| 249 | | group by fg.name; |
| 250 | | go |
| 251 | | }}} |
| 252 | | |
| 253 | | ==== Partition elimination |
| 254 | | |
| 255 | | {{{#!sql |
| 256 | | set statistics io on |
| 257 | | select count(*) from encounters where [start] >= '2022-01-01'; |
| 258 | | set statistics io off; |
| 259 | | }}} |
| | 6 | * [wiki:FileGroups распределба на податоците во `filegroups` по временски период] |
| | 7 | * [wiki:Partitioning партиционирање по датум (година/деценија) и clustered индекси поставени на партициска шема за да се активира партиционирањето] |
| | 8 | * [wiki:PartitioningVerification верификација на партиционирањето] |