space_used.tcl 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. # Run this TCL script using "testfixture" in order get a report that shows
  2. # how much disk space is used by a particular data to actually store data
  3. # versus how much space is unused.
  4. #
  5. # Get the name of the database to analyze
  6. #
  7. if {[llength $argv]!=1} {
  8. puts stderr "Usage: $argv0 database-name"
  9. exit 1
  10. }
  11. set file_to_analyze [lindex $argv 0]
  12. # Open the database
  13. #
  14. sqlite db [lindex $argv 0]
  15. set DB [btree_open [lindex $argv 0]]
  16. # Output the schema for the generated report
  17. #
  18. puts \
  19. {BEGIN;
  20. CREATE TABLE space_used(
  21. name clob, -- Name of a table or index in the database file
  22. is_index boolean, -- TRUE if it is an index, false for a table
  23. payload int, -- Total amount of data stored in this table or index
  24. pri_pages int, -- Number of primary pages used
  25. ovfl_pages int, -- Number of overflow pages used
  26. pri_unused int, -- Number of unused bytes on primary pages
  27. ovfl_unused int -- Number of unused bytes on overflow pages
  28. );}
  29. # This query will be used to find the root page number for every index and
  30. # table in the database.
  31. #
  32. set sql {
  33. SELECT name, type, rootpage FROM sqlite_master
  34. UNION ALL
  35. SELECT 'sqlite_master', 'table', 2
  36. ORDER BY 1
  37. }
  38. # Initialize variables used for summary statistics.
  39. #
  40. set total_size 0
  41. set total_primary 0
  42. set total_overflow 0
  43. set total_unused_primary 0
  44. set total_unused_ovfl 0
  45. # Analyze every table in the database, one at a time.
  46. #
  47. foreach {name type rootpage} [db eval $sql] {
  48. set cursor [btree_cursor $DB $rootpage 0]
  49. set go [btree_first $cursor]
  50. set size 0
  51. catch {unset pg_used}
  52. set unused_ovfl 0
  53. set n_overflow 0
  54. while {$go==0} {
  55. set payload [btree_payload_size $cursor]
  56. incr size $payload
  57. set stat [btree_cursor_dump $cursor]
  58. set pgno [lindex $stat 0]
  59. set freebytes [lindex $stat 4]
  60. set pg_used($pgno) $freebytes
  61. if {$payload>238} {
  62. set n [expr {($payload-238+1019)/1020}]
  63. incr n_overflow $n
  64. incr unused_ovfl [expr {$n*1020+238-$payload}]
  65. }
  66. set go [btree_next $cursor]
  67. }
  68. btree_close_cursor $cursor
  69. set n_primary [llength [array names pg_used]]
  70. set unused_primary 0
  71. foreach x [array names pg_used] {incr unused_primary $pg_used($x)}
  72. regsub -all ' $name '' name
  73. puts -nonewline "INSERT INTO space_used VALUES('$name'"
  74. puts -nonewline ",[expr {$type=="index"}]"
  75. puts ",$size,$n_primary,$n_overflow,$unused_primary,$unused_ovfl);"
  76. incr total_size $size
  77. incr total_primary $n_primary
  78. incr total_overflow $n_overflow
  79. incr total_unused_primary $unused_primary
  80. incr total_unused_ovfl $unused_ovfl
  81. }
  82. # Output summary statistics:
  83. #
  84. puts "-- Total payload size: $total_size"
  85. puts "-- Total pages used: $total_primary primary and $total_overflow overflow"
  86. set file_pgcnt [expr {[file size [lindex $argv 0]]/1024}]
  87. puts -nonewline "-- Total unused bytes on primary pages: $total_unused_primary"
  88. if {$total_primary>0} {
  89. set upp [expr {$total_unused_primary/$total_primary}]
  90. puts " (avg $upp bytes/page)"
  91. } else {
  92. puts ""
  93. }
  94. puts -nonewline "-- Total unused bytes on overflow pages: $total_unused_ovfl"
  95. if {$total_overflow>0} {
  96. set upp [expr {$total_unused_ovfl/$total_overflow}]
  97. puts " (avg $upp bytes/page)"
  98. } else {
  99. puts ""
  100. }
  101. set n_free [expr {$file_pgcnt-$total_primary-$total_overflow}]
  102. if {$n_free>0} {incr n_free -1}
  103. puts "-- Total pages on freelist: $n_free"
  104. puts "COMMIT;"