Database | Proc | Application | Created | Links |
sybsystemprocs | sp_spaceusage_object_populate ![]() | ![]() | 31 Aug 14 | Defects Dependencies |
1 2 /* 3 ** SP_SPACEUSAGE_OBJECT_POPULATE 4 ** 5 ** The sub-procedure that populates the temporary table #spaceusageinfo 6 ** with computed space usage information based on the raw space usage 7 ** information already in it. This is applicable only for the "display", 8 ** "display summary" and "archive" action. Called by sp_spaceusage_object. 9 ** 10 ** Parameters 11 ** None. 12 ** 13 ** Returns 14 ** 0 - if all goes well 15 ** other - error while execution 16 { 17 */ 18 create procedure sp_spaceusage_object_populate 19 as 20 begin -- { 21 22 declare 23 @objid int 24 , @indid int 25 , @ptnid int 26 , @lockscheme tinyint 27 28 , @syscur_ffactor float -- server-wide fill factor % 29 , @syscur_ers_pct float -- server-wide exp row size % 30 31 , @datalayerpages int 32 , @datapartitionid int 33 , @numrowscovered float 34 , @indexrowsize float 35 36 , @numpagesPerExtent int 37 , @numextent0 int 38 , @dummyindexlevel smallint 39 , @aplpagehdrsize tinyint 40 , @dolpagehdrsize tinyint 41 42 , @returnStatus int 43 , @msg varchar(256) 44 45 select @dummyindexlevel = - 1 46 , @numpagesPerExtent = 8 47 , @numextent0 = 1 48 , @aplpagehdrsize = 32 49 , @dolpagehdrsize = 44 50 51 /* 52 ** Get the current server wide default value for the ERS and FF. 53 ** 54 ** NOTE: These values are not available in syscurconfigs, and hence, 55 ** need to get them from sysconfigures. 56 */ 57 select @syscur_ers_pct = value / 100.0 58 from master.dbo.sysconfigures 59 where comment = 'default exp_row_size percent' 60 61 select @syscur_ffactor = value / 100.0 62 from master.dbo.sysconfigures 63 where comment = 'default fill factor percent' 64 65 /* 66 ** If not set(NULL), or set to 0 or NULL, handle it apprpriately as this 67 ** will be used later during space calculations. 68 */ 69 select @syscur_ffactor = case @syscur_ffactor 70 when NULL then 1 71 when 0 then 1 72 else @syscur_ffactor 73 end 74 75 select @syscur_ers_pct = case @syscur_ers_pct 76 when NULL then 0 77 when 1 then 0 78 else @syscur_ers_pct 79 end 80 81 82 /* 83 ** Pull out space utilizaton and cluster ratio using the derived_stat() 84 ** built-in. This may need to be converted into appropriate format 85 ** before display to be in synch with other related output columns. 86 ** Also, the derived_stat() built-in requires SA role (for objects not 87 ** owned by the user running the built-in) and will be displayed only 88 ** when this sproc is run with that role. Else, it will show 0. 89 */ 90 update #spaceusageinfo 91 set SpUtil = convert(decimal(9, 2), 92 100 * derived_stat(Id, IndId, PtnId, 93 "space utilization")) 94 , DPCR = convert(decimal(5, 4), 95 derived_stat(Id, IndId, PtnId, "dpcr")) 96 , DRCR = convert(decimal(5, 4), 97 derived_stat(Id, IndId, PtnId, "drcr")) 98 , IPCR = convert(decimal(5, 4), 99 derived_stat(Id, IndId, PtnId, "ipcr")) 100 , LGIO = convert(decimal(5, 4), 101 derived_stat(Id, IndId, PtnId, "lgio")) 102 where OwnerName = user_name() 103 or charindex("sa_role", show_role()) > 0 104 105 if (@@error != 0) 106 return (@@error) 107 108 /* 109 ** Compute and update current value for some space related metrics 110 ** like extent utilization (ratio of the pages in use to the pages 111 ** reserved), PctEmptyPages (ratio of the empty pages to the total 112 ** pages in use), PctFwdRows (ratio of the number of forwarded rows to 113 ** the total rows respectively). 114 */ 115 update #spaceusageinfo 116 set ExtentUtil = convert(decimal(5, 2), 117 case RsvdPageCount 118 when 0 then 0 119 else UsedPageCount * 100.0 / RsvdPageCount 120 end) 121 122 , PctEmptyPages = convert(decimal(5, 2), 123 case 124 when DataPageCount = 0 then 0 125 when (EmptyPageCount / DataPageCount) > 9.99 126 then 999.99 127 else EmptyPageCount * 100.0 / DataPageCount 128 end) 129 , PctFwdRows = convert(decimal(5, 2), 130 case NumRows 131 when 0 then 0 132 else NumFwdRows * 100.0 / NumRows 133 end) 134 135 if (@@error != 0) 136 return (@@error) 137 138 update #spaceusageinfo 139 set NumVarCols = (select count(*) 140 from syscolumns i 141 where i.id = #spaceusageinfo.Id 142 and i.offset < 0) 143 144 if (@@error != 0) 145 return (@@error) 146 147 /* 148 ** For data layer pages (indid = 0), calculate the space per page 149 ** available as follows. 150 ** 151 ** Adjust for the page header, to get the actual row-storage space on 152 ** a page. 153 ** 154 ** Apply fill factor as follows: 155 ** APL table with CI (indid = 1), if value stored in sysindexes for 156 ** indid 1, use it. If not, use the server wide default value. 157 ** 158 ** DOL table (indid=0), if value stored in sysindexes for indid 0, 159 ** use it. If not, fully pack it. 160 ** 161 ** Apply expected row size as follows: 162 ** Applicable only for DOL tables with variable length columns. 163 ** 164 ** If set to 0, use the server wide default expected row size 165 ** percent to leave space in each row for expanding rows. 166 ** 167 ** If set to 1, we fully pack the data page. 168 ** 169 ** If set to any other value, then it will be taken care of later 170 ** (w.r.t to data row size value) 171 */ 172 update #spaceusageinfo 173 set SpacePerPage = (@@maxpagesize - @aplpagehdrsize) 174 * 175 (case FF 176 when NULL then 1 177 when 0 then @syscur_ffactor 178 else FF / 100.0 179 end) 180 where IndId = 0 181 and LockScheme = 0 -- APL table 182 183 if (@@error != 0) 184 return (@@error) 185 186 update #spaceusageinfo 187 set SpacePerPage = (@@maxpagesize - @dolpagehdrsize) 188 * 189 (case FF 190 when NULL then 1 191 when 0 192 then case 193 when NumVarCols > 0 194 and ERS = 0 195 then (1 - @syscur_ers_pct) 196 else 1 197 end 198 else FF / 100.0 199 end) 200 where IndId = 0 201 and LockScheme != 0 -- non-APL, i.e., DOL table 202 203 if (@@error != 0) 204 return (@@error) 205 206 /* 207 ** Calculate the number of data rows that can fit a single page based on 208 ** the space available per page for rows and the row size. 209 ** 210 ** For DOL tables, if ERS is set [to a value other than 0/1], inserts 211 ** reserve that much space for the row even if currently it is smaller 212 ** in size in case the table has variable length columns. 213 ** 214 ** Figure in a 2-byte offset table overhead. 215 */ 216 update #spaceusageinfo 217 set CalcRowsPerPage = SpacePerPage / (case LockScheme 218 when 0 then RowSize 219 else case --DOL 220 when ERS is not NULL 221 and ERS != 0 222 and ERS != 1 223 and ERS > RowSize 224 and NumVarCols > 0 225 then ERS 226 else RowSize 227 end 228 end 229 + 2) -- Row offset entry size 230 where IndId = 0 231 232 if (@@error != 0) 233 return (@@error) 234 235 /* 236 ** For APL tables, if MRPP is set, it limits the no of rows that can fit 237 ** a page. Also, an APL table can not have more than 256 rows per page. 238 */ 239 update #spaceusageinfo 240 set CalcRowsPerPage = case 241 when MRPP != 0 242 and MRPP < CalcRowsPerPage 243 then MRPP 244 else case 245 when CalcRowsPerPage > 256.0 246 then 256.0 247 else CalcRowsPerPage 248 end 249 end 250 where IndId = 0 and LockScheme = 0 -- APL data layer 251 252 if (@@error != 0) 253 return (@@error) 254 255 /* 256 ** Update the temp table to get the estimated data layer pages that 257 ** would be required if this were a fully packed table. 258 ** 259 ** If the number of rows in the table is 0, then the expected data pages 260 ** for the data layer is 1. 261 */ 262 update #spaceusageinfo 263 set ExpDataPageCount = case NumRows 264 when 0 then 1 265 else ceiling(NumRows / CalcRowsPerPage) 266 end 267 where IndId = 0 268 269 if (@@error != 0) 270 return (@@error) 271 272 /* 273 ** Estimate number of used pages based on the data page estimate 274 ** assuming the same number of pages will be used for internal 275 ** structures as are being used currently. 276 */ 277 update #spaceusageinfo 278 set ExpUsedPageCount = ExpDataPageCount + (UsedPageCount 279 - DataPageCount) 280 where IndId = 0 281 282 if (@@error != 0) 283 return (@@error) 284 285 /* 286 ** For the text/image index [indid = 255] there isn't a way to estimate 287 ** the number of data/used pages. So, set it to DataPageCount/ 288 ** UsedPageCount. 289 */ 290 update #spaceusageinfo 291 set ExpDataPageCount = DataPageCount 292 , ExpUsedPageCount = UsedPageCount 293 where IndId = 255 294 295 if (@@error != 0) 296 return (@@error) 297 298 /* 299 ** Set the non-leaf row size for indid > 0 except for the text/image 300 ** index[indid = 255]. 301 ** 302 ** For APL tables, the non-leaf row is same as leaf row for CI, and 303 ** has an additional 4 byte pointer [to an index page] in case of NCI. 304 ** 305 ** Ignoring the suffix compression at non-leaf levels and the duplicate 306 ** key handling at the leaf level, in DOL tables, the non-leaf rows has 307 ** a 4 byte pointer in place of the 6 byte RID of the leaf rows. 308 ** 309 ** NOTE: For indid = 1, leaf row size is not maintained and will be 310 ** computed later. This step will actually set it is as data row size. 311 ** 312 */ 313 update #spaceusageinfo 314 set NonLeafRowSize = case LockScheme 315 when 0 then (case IndId 316 when 1 then (RowSize) 317 else (RowSize + 4) 318 end) 319 else (RowSize - 6 + 4) 320 end 321 where IndId > 0 and IndId != 255 322 323 if (@@error != 0) 324 return (@@error) 325 326 /* 327 ** Compute/Estimate the ExpDataPageCount for the index layer [indid>0] 328 ** 329 ** Steps involved - 330 ** 1. set the #indexData table [by selecting from #spaceusageinfo 331 ** into it]. at this point, the leaf and non-leaf row sizes are 332 ** already computed and set. sp_index_space_est will compute the 333 ** leaf and non-leaf rows per page values internally based on 334 ** them. 335 ** 336 ** 2. go thru eachthreesome and pass it to the 337 ** sp_index_space_est. this sproc would set the data pages and 338 ** used pages for this 345 346 /* STEP 1. 347 ** Create and populate the #indexData table required by the sproc 348 ** sp_index_space_est which will be used to calculate the 349 ** ExpDataPageCount, ExpUsedPageCount, ExpRsvdPageCount for the index 350 ** layer [indid >0] 351 */ 352 select Id as id 353 , IndId as indid 354 , PtnId as ptnid 355 , IndexName as name 356 , "" as type 357 , - 1 as indexlevel 358 , convert(smallint NULL, FF) as ffactor 359 , convert(smallint NULL, MRPP) as maxrowsperpage 360 , convert(int NULL, 0) as datalayerpages 361 , convert(float NULL, NumRows) as numrows 362 , convert(float NULL, RowSize) as leafrowsize 363 , convert(float NULL, NonLeafRowSize) as nonleafrowsize 364 , convert(tinyint NULL, LockScheme) as lockscheme 365 , 0 as numofdatapages 366 , convert(float, 0) as datasizeinkb 367 , 0 as numofusedpages 368 , convert(float, 0) as usedsizeinkb 369 into #indexData 370 from #spaceusageinfo 371 where IndId > 0 372 and IndId != 255 373 374 if (@@error != 0) 375 return (@@error) 376 377 /* 378 ** Create a unique index on #indexData in order to create an updatable 379 ** cursor on it. 380 */ 381 create unique index uind on #indexData(id, indid, ptnid, indexlevel) 382 383 if (@@error != 0) 384 return (@@error) 385 386 /* STEP 2. 387 ** Compute the no. of index pages and used pages for the indices one at 388 ** a time using the sp_index_space_est sproc. 389 */ 390 declare indexcursor cursor for 391 select id, indid, ptnid, lockscheme 392 from #indexData 393 where indexlevel = @dummyindexlevel 394 for update 395 396 open indexcursor 397 398 while (1 = 1) 399 begin -- { 400 401 -- Go to the nextthreesome in the 339 ** #indexData table appropriately. 340 ** 341 ** 3. set the ExpDataPageCount and ExpUsedPageCount in 342 ** #spaceusageinfo table for the index accordingly. 343 ** 344 */ quad. 402 fetch indexcursor into @objid, @indid, @ptnid, @lockscheme 403 404 if @@sqlstatus != 0 405 break 406 407 -- For indid = 1, the index row size is not maintained. So, we 408 -- will use the sproc sp_index_row_size_est to get a rough 409 -- estimate for it. 410 -- 411 if @indid = 1 412 begin -- { 413 exec @returnStatus = sp_index_row_size_est 414 @objid 415 , @indid 416 , @lockscheme 417 , NULL 418 , @indexrowsize out 419 420 if @returnStatus != 0 421 return (@returnStatus) 422 423 -- Update the leaf row size and non leaf row size with 424 -- the estimated index row size both for #indexData 425 -- [needed for index space estimate] and #spaceusageinfo 426 -- [needed as it is the repository for all the collected 427 -- data] 428 -- 429 update #indexData 430 set leafrowsize = @indexrowsize 431 , nonleafrowsize = @indexrowsize 432 where id = @objid 433 and indid = @indid 434 and ptnid = @ptnid 435 and indexlevel = @dummyindexlevel 436 437 if (@@error != 0) 438 return (@@error) 439 440 update #spaceusageinfo 441 set RowSize = @indexrowsize 442 , NonLeafRowSize = @indexrowsize 443 where Id = @objid 444 and IndId = @indid 445 and PtnId = @ptnid 446 447 if (@@error != 0) 448 return (@@error) 449 450 end --} -- End of if 451 452 -- Fetch the data partition id corresponding to the index. 453 select @datapartitionid = DataPtnId 454 from #spaceusageinfo 455 where Id = @objid 456 and IndId = @indid 457 and PtnId = @ptnid 458 459 if (@datapartitionid = 0) 460 begin 461 462 -- Global, unpartitioned index covering all data 463 -- partitions. 464 -- 465 select @datalayerpages = sum(ExpDataPageCount) 466 , @numrowscovered = sum(NumRows) 467 from #spaceusageinfo 468 where Id = @objid 469 and IndId = 0 470 end 471 else 472 begin 473 474 -- Local, partitioned index covering a single 475 -- partition. 476 -- 477 -- APL CI are on same partition as the data they cover 478 -- For them the partition ID and the data partition ID 479 -- would always match. 480 -- 481 select @datalayerpages = ExpDataPageCount 482 , @numrowscovered = NumRows 483 from #spaceusageinfo 484 where Id = @objid 485 and IndId = 0 486 and PtnId = @datapartitionid 487 end 488 489 update #indexData 490 set datalayerpages = @datalayerpages 491 , numrows = @numrowscovered 492 where id = @objid 493 and indid = @indid 494 and ptnid = @ptnid 495 and indexlevel = @dummyindexlevel 496 497 if (@@error != 0) 498 return (@@error) 499 500 -- Get the index space estimate for the501 -- threesome. 502 -- 503 exec @returnStatus = sp_index_space_est @objid, @indid, @ptnid 504 505 if @returnStatus != 0 506 return (@returnStatus) 507 508 -- Consolidate the result. 509 -- 510 -- sp_index_space_est sums up all the index layer data and used 511 -- pages for each level and sets the numofdatapages and 512 -- numofusedpages columns for the indexlevel = -1 row with that 513 -- value. We set ExpDataPageCount and ExpUsedPageCount of 514 -- #spaceusageinfo table to those values. 515 -- 516 update #spaceusageinfo 517 set ExpDataPageCount = (select numofdatapages 518 from #indexData 519 where id = @objid 520 and indid = @indid 521 and ptnid = @ptnid 522 and indexlevel = 523 @dummyindexlevel) 524 , ExpIndexHeight = (select max(indexlevel) 525 from #indexData 526 where id = @objid 527 and indid = @indid 528 and ptnid = @ptnid) 529 530 where Id = @objid 531 and IndId = @indid 532 and PtnId = @ptnid 533 534 if (@@error != 0) 535 return (@@error) 536 537 -- Instead of using the numofusedpages from #indexData as the 538 -- estimate for ExpUsedPageCount, use the current internal 539 -- structure overhead (UsedPageCount - DataPageCount) and add it 540 -- to ExpDataPageCount to get the ExpUsedPageCount. 541 -- 542 update #spaceusageinfo 543 set ExpUsedPageCount = ExpDataPageCount + 544 (UsedPageCount - DataPageCount) 545 where Id = @objid 546 and IndId = @indid 547 and PtnId = @ptnid 548 549 if (@@error != 0) 550 return (@@error) 551 552 -- Set the ExpLeafPageCount of #spaceusageinfo table. For indid 553 -- 1, the leaf pages are same as the data pages. 554 -- 555 update #spaceusageinfo 556 set ExpLeafPageCount = case IndId 557 when 1 then 0 558 else (select numofdatapages 559 from #indexData 560 where id = @objid 561 and indid = @indid 562 and ptnid = @ptnid 563 and indexlevel = 0) 564 end 565 where Id = @objid 566 and IndId = @indid 567 and PtnId = @ptnid 568 569 if (@@error != 0) 570 return (@@error) 571 572 end -- } -- End of while 573 574 close indexcursor 575 deallocate cursor indexcursor 576 577 /* 578 ** Go back and update expected reserved pages rounding up the expected 579 ** data pages to a multiple of # of extents. 580 ** 581 ** Incorporate the reserve page gap as follows. For CI, RPG applies 582 ** to both the data and index pages and for NCI it applies to only 583 ** data pages and leaf level pages. 584 */ 585 update #spaceusageinfo 586 set ExpRsvdPageCount = ceiling((ExpUsedPageCount 587 + case RPG 588 when 0 then 0.0 589 else 590 ceiling( 591 (1.0 / RPG) * 592 case 593 when IndId <= 1 594 then ExpUsedPageCount 595 else ExpLeafPageCount 596 end 597 ) 598 end 599 ) / @numpagesPerExtent 600 ) * @numpagesPerExtent 601 602 if (@@error != 0) 603 return (@@error) 604 605 /* 606 ** Now that we have got the expected data/reserved page counts, 607 ** compute the %age bloat values. 608 */ 609 update #spaceusageinfo 610 set PctBloatRsvdPages = (convert(float, (RsvdPageCount 611 - ExpRsvdPageCount)) 612 / ExpRsvdPageCount) * 100 613 , PctBloatUsedPages = (convert(float, (UsedPageCount 614 - ExpUsedPageCount)) 615 / ExpUsedPageCount) * 100 616 where ExpUsedPageCount > 0 617 618 update #spaceusageinfo 619 set PctBloatLeafPages = (convert(float, (LeafPageCount 620 - ExpLeafPageCount)) 621 / ExpLeafPageCount) * 100 622 where ExpLeafPageCount > 0 623 624 if (@@error != 0) 625 return (@@error) 626 627 /* 628 ** Raise a warning message if the values were found suspicious. 629 ** 630 ** This message might come up often when space parameters are set. This 631 ** is because the procedure takes them into account even though they 632 ** might have not been applied yet. 633 ** 634 ** Also, the expected reserved pages may be off by the number of extent0 635 ** extents allocated to the object because the AP in extent0 is counted 636 ** by our estimates whereas in reality that is not the case. There's no 637 ** way to get this number for an object, we assume it to be 1 here. The 638 ** variable @numextent0 should be changed appropriately if this number 639 ** is tracked, or can be derived, in future. 640 */ 641 if exists (select 1 642 from #spaceusageinfo 643 where (PctBloatRsvdPages < 0 644 and (ExpRsvdPageCount - RsvdPageCount) > 645 @numextent0 646 ) 647 or PctBloatUsedPages < 0 648 or PctBloatLeafPages < 0 649 or PctFwdRows < 0 650 or PctEmptyPages < 0 651 or PctEmptyPages > 100 652 ) 653 begin 654 exec sp_getmessage 19532, @msg out 655 print @msg, "UPDATE [TABLE] STATISTICS" 656 end 657 658 end -- } -- } 659
exec sp_procxmode 'sp_spaceusage_object_populate', 'AnyMode' go Grant Execute on sp_spaceusage_object_populate to public go
DEPENDENCIES |
PROCS AND TABLES USED reads table sybsystemprocs..syscolumns ![]() calls proc sybsystemprocs..sp_index_row_size_est ![]() reads table sybsystemprocs..syscolumns ![]() reads table sybsystemprocs..sysindexes ![]() reads table sybsystemprocs..sysobjects ![]() calls proc sybsystemprocs..sp_index_space_est ![]() reads table sybsystemprocs..sysindexes ![]() reads table master..syscurconfigs (1) ![]() read_writes table tempdb..#indexData (1) calls proc sybsystemprocs..sp_getmessage ![]() reads table master..sysmessages (1) ![]() reads table master..syslanguages (1) ![]() calls proc sybsystemprocs..sp_validlang ![]() reads table master..syslanguages (1) ![]() reads table sybsystemprocs..sysusermessages ![]() read_writes table tempdb..#indexData (1) read_writes table tempdb..#spaceusageinfo (1) reads table master..sysconfigures (1) ![]() CALLERS called by proc sybsystemprocs..sp_spaceusage_object ![]() called by proc sybsystemprocs..sp_spaceusage ![]() |