Detaillierte Erläuterung der MySQL Innodb-Speicherstruktur und der Speicherung von Nullwerten

Detaillierte Erläuterung der MySQL Innodb-Speicherstruktur und der Speicherung von Nullwerten

Hintergrund:

Tablespace: Alle INNODB-Daten werden im Tablespace gespeichert (gemeinsamer Tablespace). Wenn innodb_file_per_table aktiviert ist, werden die Daten jeder Tabelle in einem separaten Tablespace gespeichert (exklusiver Tablespace).
Zu den exklusiven Tablespaces gehören: Daten, Index, Einfügecache und Datenwörterbuch. Der gemeinsam genutzte Tabellenbereich umfasst: Undo-Informationen (<physischer Speicherplatz> wird nicht zurückgefordert), Informationen zum Double-Write-Cache, Transaktionsinformationen usw.
Segment: Es bildet den Tabellenbereich und besteht aus Zonen.
Umfang: besteht aus 64 zusammenhängenden Seiten. Jede Seite ist 16 KB groß, also insgesamt 1 Million. Bei großen Datensegmenten können jeweils 4 Zonen angewendet werden.
Seite: Dies ist die Einheit der INNODB-Datenträgerverwaltung und besteht aus Zeilen.
Zeile: enthält Transaktions-ID, Rollback-Zeiger, Spalteninformationen usw.

Zweck 1:
Verstehen Sie die Informationen jeder Seite des Tabellenbereichs und die Speicherung von Überlaufzeilendaten. Mithilfe des vom Buchautor Jiang Chengyao geschriebenen Tools: http://code.google.com/p/david-mysql-tools/source/browse/trunk/py_innodb_page_type/
3 Skripte:

py_innodb_page_info.py

Code anzeigen 

#!/usr/bin/env python 
#Kodierung=utf-8
mylib importieren
von sys importiere argv
von mylib importiere myargv

wenn __name__ == '__main__':
 meinargv = meinargv(argv)
 wenn myargv.parse_cmdline() == 0:
  passieren
 anders:
  mylib.get_innodb_page_type(myargv)

mylib.py

Code anzeigen 

Kodierung=utf-8
Betriebssystem importieren
Importieren Sie Include
von include import *

TABLESPACE_NAME='D:\\mysql_data\\test\\t.ibd'
VARIABLE_FIELD_COUNT = 1
NULL_FIELD_COUNT = 0

Klasse myargv (Objekt):
 def __init__(selbst, argv):
  selbst.argv = argv
  selbst.parms = {}
  selbst.tablespace = ''

 def parse_cmdline(selbst):
  argv = selbst.argv
  wenn len(argv) == 1:
   drucken 'Verwendung: python py_innodb_page_info.py [OPTIONEN] tablespace_file'
   drucken 'Für weitere Optionen verwenden Sie python py_innodb_page_info.py -h'
   Rückgabe 0
  während argv:
   wenn argv[0][0] == '-':
    wenn argv[0][1] == 'h':
     self.parms[argv[0]] = ''
     argv = argv[1:]
     brechen
    wenn argv[0][1] == 'v':
     self.parms[argv[0]] = ''
     argv = argv[1:]
    anders:
     selbst.parms[argv[0]] = argv[1]
     argv = argv[2:]
   anders:
    selbst.tablespace = argv[0]
    argv = argv[1:]
  wenn self.parms.has_key('-h'):
   print 'InnoDB-Seiteninformationen abrufen'
   drucken 'Verwendung: python py_innodb_page_info.py [OPTIONEN] tablespace_file\n'
   print 'Die folgenden Optionen können als erstes Argument angegeben werden:'
   drucke '-h Hilfe '
   print '-o output, schreib das Ergebnis in eine Datei'
   print '-t Nummer des Threads zum Analysieren der Tablespace-Datei'
   print '-v ausführlicher Modus'
   Rückgabe 0
  Rückgabe 1

def mach_read_from_n(Seite, Start-Offset, Länge):
 ret = Seite[Startoffset:Startoffset+Länge]
 returniere ret.encode('hex')

auf jeden Fall get_innodb_page_type(myargv):
 f = Datei(myargv.tablespace,'rb')
 fsize = os.path.getsize(f.name)/INNODB_PAGE_SIZE
 ret = {}
 für i im Bereich (fsize):
  Seite = f.lesen(INNODB_PAGE_SIZE)
  Seitenoffset = mach_read_from_n(Seite,FIL_SEITENOFFSET,4)
  Seitentyp = mach_read_from_n(Seite,FIL_SEITENTYP,2)
  wenn myargv.parms.has_key('-v'):
   wenn Seitentyp == '45bf':
    Seitenebene = mach_read_from_n(Seite,FIL_SEITENDATEN+SEITENEBENE,2)
    drucken "Seitenoffset %s, Seitentyp <%s>, Seitenebene <%s>"%(Seitenoffset,innodb_Seitentyp[Seitentyp],Seitenebene)
   anders:
    drucken "Seitenoffset %s, Seitentyp <%s>"%(Seitenoffset,innodb_Seitentyp[Seitentyp])
  wenn nicht ret.has_key(page_type):
   ret[Seitentyp] = 1
  anders:
   ret[Seitentyp] = ret[Seitentyp] + 1
 print "Gesamtzahl der Seiten: %d:"%fsize
 für Typ in ret:
  drucken "%s: %s"%(innodb_page_type[Typ],ret[Typ])

include.py

Code anzeigen 

#Kodierung=utf-8
INNODB_PAGE_SIZE = 16*1024*1024

# Beginn der Daten auf der Seite
FIL_PAGE_DATA = 38


FIL_PAGE_OFFSET = 4 # Seitenversatz innerhalb des Leerzeichens
FIL_PAGE_TYPE = 24 # Dateiseitentyp

# Typen eines Undo-Log-Segments */
TRX_UNDO_INSERT = 1
TRX_UNDO_UPDATE = 2

# Auf einer Seite eines beliebigen Dateisegments können Daten ab diesem Offset abgelegt werden
FSEG_PAGE_DATA = FIL_PAGE_DATA

# Der Offset des Undo-Log-Seitenkopfes auf den Seiten des Undo-Logs
TRX_UNDO_PAGE_HDR = FSEG_PAGE_DATA

PAGE_LEVEL = 26 #Ebene des Knotens in einem Indexbaum; die Blattebene ist die Ebene 0 */

innodb_page_type={
 '0000':u'Neu zugewiesene Seite',
 '0002':u'Protokollseite rückgängig machen',
 '0003':u'Dateisegment-Inode',
 '0004':u'Liste freier Puffer einfügen',
 '0005':u'Puffer-Bitmap einfügen',
 '0006':u'Systemseite',
 '0007':u'Transaktionssystemseite',
 '0008':u'Dateibereichsheader',
 '0009':u'Erweiterte Beschreibungsseite',
 '000a':u'Unkomprimierte BLOB-Seite',
 '000b':u'1. komprimierte BLOB-Seite',
 '000c':u'Anschließende komprimierte BLOB-Seite',
 '45bf':u'B-Baum-Knoten'
 }

innodb_page_direction={
 '0000': 'Unbekannt(0x0000)',
 '0001': 'Seite links',
 '0002': 'Seite rechts',
 '0003': 'Gleiche Aufnahme aufrufen',
 '0004': 'Seite Gleiche Seite',
 '0005': 'Seitennummer Richtung',
 'ffff': 'Unbekannt2(0xffff)'
}


INNODB_PAGE_SIZE=1024*16 # InnoDB Seite 16K

Prüfung 1:

root@localhost: Test 02:26:13>Tabelle erstellen tt(ID int auto_increment,Name varchar(10),Alter int,Adresse varchar(20),Primärschlüssel (ID))Engine=innodb;
Abfrage OK, 0 Zeilen betroffen (0,17 Sek.)
root@zhoujy:/var/lib/mysql/test# ls -lh tt.ibd 
-rw-rw---- 1 MySQL MySQL 96K 17.10.2012 14:26 tt.ibd

IBD anzeigen:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v
Seitenoffset 00000000, Seitentyp <File Space Header>
Seitenoffset 00000001, Seitentyp <Puffer-Bitmap einfügen>
Seitenoffset 00000002, Seitentyp <Dateisegment-Inode>
Seitenoffset 00000003, Seitentyp <B-Baumknoten>, Seitenebene <0000> --- Seitenoffset des Blattknotens 00000000, Seitentyp <Frisch zugewiesene Seite>
Seitenoffset 00000000, Seitentyp <Frisch zugewiesene Seite>
Gesamtseitenzahl: 6: 
Neu zugewiesene Seite: 2
Puffer-Bitmap einfügen: 1
Dateibereichsheader: 1
B-Baum-Knoten: 1
Dateisegment-Inode: 1

erklären:
Gesamtseitenzahl: Gesamtseitenzahl
Neu zugewiesene Seite: Verfügbare Seite
Pufferbitmap einfügen: Cache-Bitmapseite einfügen
Pufferfreie Liste einfügen: Seite mit Cache-Freiliste einfügen
B-Baum-Knoten: Datenseite
Unkomprimierte BLOB-Seite: Binäre Großobjektseite, die Seite, die Überlaufzeilen speichert. Das heißt, die auf der Überlaufseite erhaltene Information ist, dass die Initialisierungsgröße der Tabelle 96 KB beträgt, was sich aus der Gesamtzahl der Seiten * 16 ergibt. 1 Datenseite, 2 Freiseiten.

root@localhost: Test 02:42:58> in tt-Werte einfügen (Name, Alter, Adresse) Werte („aaa“, 23, „HZZZ“);

Frage: Warum gibt es kein Anwendungsgebiet? Eine Zone besteht aus 64 aufeinanderfolgenden Seiten und ist 1 MB groß. Dann sollte die Tabellengröße auch mindestens 1 MB betragen. Aber jetzt sind es nur 96 KB (Standard). Der Grund dafür ist, dass zu Beginn jedes Segments 32 Seiten fragmentierter Seiten zum Speichern von Daten vorhanden sind. Nachdem diese aufgebraucht sind, werden kontinuierlich 64 Seiten angewendet. Es können jedes Mal maximal 4 Bereiche angewendet werden, um die Reihenfolge der Daten sicherzustellen. Hier ist ersichtlich, dass sich die Tabellengröße um mindestens 64 Seiten vergrößert, also um 1 MB.
verifizieren:
Füllen Sie die 32 Fragmentseiten mit Daten, 32*16 = 512 KB. Prüfen Sie, ob Sie sich für einen Platz größer als 1 m bewerben können.

Code anzeigen 

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd 
-rw-rw---- 1 mysql mysql 576K 17.10.2012 15:30 /var/lib/mysql/test/tt.ibd
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v
Seitenoffset 00000000, Seitentyp <File Space Header>
Seitenoffset 00000001, Seitentyp <Puffer-Bitmap einfügen>
Seitenoffset 00000002, Seitentyp <Dateisegment-Inode>
Seitenoffset 00000003, Seitentyp <B-Baumknoten>, Seitenebene <0001>
Seitenoffset 00000004, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000005, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000006, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000007, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000008, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000009, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000000a, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000000b, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000000c, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000000d, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000000e, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000000f, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000010, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000011, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000012, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000013, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000014, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000015, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000016, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000017, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000018, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000019, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000001a, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000001b, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000001c, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000001d, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000001e, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 0000001f, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000020, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000021, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000022, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000023, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Gesamtseitenzahl: 36:
Puffer-Bitmap einfügen: 1
Dateibereichsheader: 1
B-Baum-Knoten: 33
Dateisegment-Inode: 1

"Extra" Seiten: 4
Seitenoffset 00000000, Seitentyp <File Space Header> : Dateiheader-Space-Seite
Seitenoffset 00000001, Seitentyp <Puffer-Bitmap einfügen>: Puffer-Bitmap-Seite einfügen
Seitenoffset 00000002, Seitentyp <Dateisegment-Inode>: Dateisegmentknoten
Seitenoffset 00000003, Seitentyp <B-Baumknoten>, Seitenebene <0001>: Stammseitenfragmentierungsseiten: 32
Seitentyp <B-Baum-Knoten>, Seitenebene <0000>
Insgesamt gibt es 36 Seiten. Der Ursprung der IBD-Größe von 576 KB lautet: 32 * 16 = 512 KB (fragmentierte Seiten) + 4 * 16 = 64 (zusätzliche Seiten). Wenn Sie mehr einfügen möchten, sollten Sie mindestens 1 Million Seiten beantragen:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd 
-rw-rw---- 1 mysql mysql 2.0M 17.10.2012 16:10 /var/lib/mysql/test/tt.ibd
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd
Gesamtseitenzahl: 128:
Frisch zugewiesene Seite: 91
Puffer-Bitmap einfügen: 1
Dateibereichsheader: 1
B-Baum-Knoten: 34
Dateisegment-Inode: 1

Die Seitengröße springt von 36 auf 128. Da 32 fragmentierte Seiten aufgebraucht sind, beantragen neue Seiten mit der Zonenmethode Platz. Die Tatsache, dass so viele Seiten mit Informationen verfügbar sind, ist ein Beweis für diese Tatsache.

▲ Überlaufzeilendatenspeicherung: Die INNODB-Speicher-Engine ist indexorganisiert, d. h. jede Seite enthält mindestens zwei Datensatzzeilen. Wenn auf einer Seite also nur eine Datensatzzeile gespeichert werden kann, legt INNODB die Zeilendaten automatisch auf der Überlaufseite ab. Wenn eine Überlaufzeile auftritt, werden die tatsächlichen Daten auf der BLOB-Seite gespeichert, und die Datenseite speichert nur die ersten 768 Bytes der Daten (altes Dateiformat). Das neue Dateiformat (Barracuda) verwendet eine vollständige Zeilenüberlaufmethode, bei der die Datenseite nur einen 20-Byte-Zeiger speichert und das BLOB auch alle Daten speichert. Wie kann ich prüfen, ob die Tabelle überlaufende Zeilendaten enthält?

root@localhost: Test 04:52:34>Tabelle t1 erstellen (ID int, Name varchar (10), Memo varchar (8000)) Engine = InnoDB-Standardzeichensatz utf8;
Abfrage OK, 0 Zeilen betroffen (0,16 Sek.)

root@localhost: Test 04:53:10> in t1-Werte einfügen (1, „zjy“, Wiederholung („我“, 8000));
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

IBD anzeigen:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/t1.ibd -v
Seitenoffset 00000000, Seitentyp <File Space Header>
Seitenoffset 00000001, Seitentyp <Puffer-Bitmap einfügen>
Seitenoffset 00000002, Seitentyp <Dateisegment-Inode>
Seitenoffset 00000003, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000004, Seitentyp <Unkomprimierte BLOB-Seite>
Seitenoffset 00000005, Seitentyp <Unkomprimierte BLOB-Seite>
Gesamtseitenzahl: 6:
Puffer-Bitmap einfügen: 1
Unkomprimierte BLOB-Seite: 2
Dateibereichsheader: 1
B-Baum-Knoten: 1
Dateisegment-Inode: 1

Aus den Informationen können wir erkennen, dass die soeben eingefügte Datensatzzeile übergelaufen ist und auf zwei BLOB-Seiten (<Unkomprimierte BLOB-Seite>) gespeichert ist. Da 1 Seite nur 16 KB groß ist und 2 Datenzeilen gespeichert werden müssen, sollte jede Datensatzzeile kleiner als 8 KB sein. Das Obige ist jedoch viel größer als 8 KB, sodass es überläuft. Dies gilt natürlich nicht für sehr große Felder. Wenn eine Tabelle 5 Felder hat, die alle varchar(512) sind [die Summe mehrerer varchars ist größer als 8 KB], wird sie ebenfalls überlaufen:

root@localhost: Test 05:08:39>Tabelle t2 erstellen (ID int, Name varchar (1000), Adresse varchar (512), Unternehmen varchar (200), xx varchar (512), Memo varchar (512), dem varchar (1000)) Engine = InnoDB-Standardzeichensatz utf8;
Abfrage OK, 0 Zeilen betroffen (0,17 Sek.)
root@localhost: Test 05:08:43> in t2-Werte einfügen (1, Wiederholung('Z',1000), Wiederholung('Z',500), Wiederholung('Z',500), Wiederholung('Z',500), Wiederholung('Z',500), Wiederholung('Za',500), Wiederholung('A',500));

1000+500+500+500+500+500=3500*3>8000 Bytes; die Zeile läuft über:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/t2.ibd -v
Seitenoffset 00000000, Seitentyp <File Space Header>
Seitenoffset 00000001, Seitentyp <Puffer-Bitmap einfügen>
Seitenoffset 00000002, Seitentyp <Dateisegment-Inode>
Seitenoffset 00000003, Seitentyp <B-Baumknoten>, Seitenebene <0000>
Seitenoffset 00000004, Seitentyp <Unkomprimierte BLOB-Seite>
Seitenoffset 00000000, Seitentyp <Frisch zugewiesene Seite>
Gesamtseitenzahl: 6:
Puffer-Bitmap einfügen: 1
Neu zugewiesene Seite: 1
Dateisegment-Inode: 1
B-Baum-Knoten: 1
Dateibereichsheader: 1
Unkomprimierte BLOB-Seite: 1

Auf der Seite <Unkomprimierte BLOB-Seite> werden die eigentlichen Daten gespeichert. Was also speichert die Datenseite? Mit Hexdump anzeigen:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# hexdump -C -v /var/lib/mysql/test/t1.ibd > t1.txt

IBD anzeigen:

Code anzeigen 

3082 0000c090 00 32 01 10 80 00 00 01 7a 6a 79 e6 88 91 e6 88 |.2......zjy.....|
3083 0000c0a0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3084 0000c0b0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3085 0000c0c0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3086 0000c0d0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3087 0000c0e0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3088 0000c0f0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3089 0000c100 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3090 0000c110 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3091 0000c120 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3092 0000c130 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3093 0000c140 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3094 0000c150 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3095 0000c160 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3096 0000c170 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3097 0000c180 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3098 0000c190 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3099 0000c1a0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3100 0000c1b0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3101 0000c1c0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3102 0000c1d0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3103 0000c1e0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3104 0000c1f0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3105 0000c200 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3106 0000c210 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3107 0000c220 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3108 0000c230 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3109 0000c240 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3110 0000c250 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3111 0000c260 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3112 0000c270 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3113 0000c280 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3114 0000c290 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3115 0000c2a0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3116 0000c2b0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3117 0000c2c0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3118 0000c2d0 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3119 0000c2e0 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3120 0000c2f0 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3121 0000c300 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3122 0000c310 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3123 0000c320 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3124 0000c330 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3125 0000c340 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3126 0000c350 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3127 0000c360 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 |................|
3128 0000c370 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 |................|
3129 0000c380 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 88 91 e6 |................|
3130 0000c390 88 91 e6 88 91 e6 88 91 e6 88 91 00 00 02 1c 00 |................|

Der Text besteht aus genau 48 Zeilen und jede Zeile ist 16 Bytes lang. 48*16=768 Bytes, was nur bestätigt, was ich zuvor gesagt habe: Die Datenseite speichert nur die ersten 768 Bytes an Daten (altes Dateiformat).

Zusammenfassung 1:
Die obigen Informationen können die Verteilung und Nutzung jeder Seite im IBD-Tabellenbereich und die Schrittweite der Tabellenbereichsvergrößerung deutlich zeigen. Achten Sie besonders auf die Überlaufzeilen. Eine Seite enthält mindestens 2 Datenzeilen. Je mehr Zeilen auf einer Seite gespeichert sind, desto besser ist die Leistung.

************************************
************************************

Zweck 2:
Verstehen Sie, wie Tablespaces Daten speichern und wie NULL-Werte gespeichert werden.

Prüfung 2:
Machen Sie sich vor dem Testen mit dem Speicherformat (row_format) von INNODB vertraut. Altes Format (Antelope): Kompakt <Standard>, Redumdant; Neues Format (Barracuda): Komprimiert, Dynamisch.
Dies testet das Standardspeicherformat.
Die kompakte Zeilenaufzeichnung erfolgt wie folgt:

 |Feldlängenliste mit variabler Länge (1–2 Bytes) |NULL-Flag (1 Byte) |Datensatzkopfinformationen (5 Bytes) |RowID (6 Bytes) |Transaktions-ID (6 Bytes) |Rollback-Zeiger (7 Bytes) |

Mit Ausnahme des „NULL-Flags“ [alle Felder in der Tabelle sind als NOT NULL definiert], „RowID“ [es gibt einen Primärschlüssel in der Tabelle] und „Liste der Feldlängen variabler Länge“ [es gibt keine Felder variabler Länge], die möglicherweise nicht vorhanden sind, werden alle anderen Informationen angezeigt. Daher sind für eine Datenzeile zusätzlich zu den von den Spaltendaten belegten Feldern noch weitere 18 Bytes erforderlich.

1: Alle Felder sind NULL

mysql> Tabelle erstellen mytest(t1 varchar(10),t2 varchar(10),t3 varchar(10),t4 varchar(10))engine=innodb charset=latin1 row_format=compact;
Abfrage OK, 0 Zeilen betroffen (0,08 Sek.)

mysql> in mytest-Werte einfügen('a','bb','bb','ccc');
Abfrage OK, 1 Zeile betroffen (0,02 Sek.)

mysql> in mytest-Werte einfügen('a','ee','ee','fff');
Abfrage OK, 1 Zeile betroffen (0,01 Sek.)

mysql> in mytest-Werte einfügen('a',NULL,NULL,'fff');
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

Nachdem die Testdaten vorbereitet sind, führen Sie den Shell-Befehl aus:

root@zhoujy:/usr/local/mysql/test# hexdump -C -v mytest.ibd > /home/zhoujy/mytest.txt

Öffnen Sie die Datei mytest.txt und suchen Sie die Zeile supremum:

0000c070 73 75 70 72 65 6d 75 6d 03 02 02 01 00 00 00 10 |supremum........| -----------> Eine Zeile, 16 Bytes 0000c080 00 25 00 00 00 03 b9 00 00 00 00 02 49 01 82 00 |.%..........I...|
0000c090 00 01 4a 01 10 61 62 62 62 62 63 63 63 03 02 02 |..J..abbbbccc...|
0000c0a0 01 00 00 00 18 00 23 00 00 00 03 b9 01 00 00 00 |......#.........|
0000c0b0 02 49 02 83 00 00 01 4b 01 10 61 65 65 65 65 66 |.I.....K..aeeeef|
0000c0c0 66 66 03 01 06 00 00 20 ff a6 00 00 00 03 b9 02 |ff..... ........|
0000c0d0 00 00 00 02 49 03 84 00 00 01 4c 01 10 61 66 66 |....I.....L..aff|
0000c0e0 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |f...............|

erklären:
Die erste Datenzeile:
03 02 02 01/*Feld mit variabler Länge*/ ---- Der Typ der 4 Felder in der Tabelle ist varchar, es gibt keine NULL-Daten und jedes Feld ist kleiner als 255.
00 /*NULL-Flag, es gibt keine Nulldaten in der ersten Zeile*/
00 00 10 00 25 /*Datensatzkopfinformationen, feste 5 Bytes*/
00 00 00 03 b9 00/*RowID, feste 6 Bytes, die Tabelle hat keinen Primärschlüssel*/
00 00 00 02 49 01 /*Transaktions-ID, feste 6 Bytes*/
82 00 00 01 4a 01 10 /*Rollback-Zeiger, feste 7 Bytes*/
61 62 62 62 62 63 63 63/* Spaltendaten*/
Die zweite Datenzeile ist identisch mit der ersten Zeile (die Farben stimmen überein).
Die Farben der dritten Datenzeile (mit NULL-Werten) und der ersten Erklärungszeile sind deutlich unterschiedlich:

03 02 02 01 VS 03 01 ----------Wenn der Wert NULL ist, belegt die Feldliste mit variabler Länge keinen Speicherplatz.
61 62 62 62 62 63 63 63 VS 61 66 66 66 --------- NULL-Werte werden nicht gespeichert und belegen keinen Speicherplatz

Fazit: Wenn der Wert NULL ist, belegt die Feldliste variabler Länge keinen Speicherplatz. NULL-Werte werden nicht gespeichert und beanspruchen keinen Platz, erfordern aber ein Flag-Bit (eines pro Zeile).

2: Alle Felder sind NICHT NULL

mysql> Tabelle erstellen mytest(t1 varchar(10) NICHT NULL,t2 varchar(10) NICHT NULL,t3 varchar(10) NICHT NULL,t4 varchar(10) NICHT NULL)engine=innodb charset=latin1 row_format=compact;
Abfrage OK, 0 Zeilen betroffen (0,03 Sek.)

mysql> in mytest-Werte einfügen('a','bb','bb','ccc');
Abfrage OK, 1 Zeile betroffen (0,01 Sek.)

mysql> in mytest-Werte einfügen('a','ee','ee','fff');
Abfrage OK, 1 Zeile betroffen (0,01 Sek.)

mysql> in mytest-Werte einfügen('a',NULL,NULL,'fff');
FEHLER 1048 (23000): Spalte 't2' kann nicht null sein

Die Schritte sind dieselben wie oben und das ibd-Ergebnis ist:

0000c070 73 75 70 72 65 6d 75 6d 03 02 02 01 00 00 10 00 |supremum........|
0000c080 24 00 00 00 03 b9 03 00 00 00 02 49 07 87 00 00 |$..........I....|
0000c090 01 4f 01 10 61 62 62 62 62 63 63 63 03 02 02 01 |.O..abbbbccc....|
0000c0a0 00 00 18 ff cb 00 00 00 03 b9 04 00 00 00 02 49 |...............Ich|
0000c0b0 08 88 00 00 01 50 01 10 61 65 65 65 65 66 66 66 |.....P..aeeeefff|

Im Vergleich zum Obigen wird festgestellt, dass die NULL-Flag-Informationen fehlen.
Fazit: Für NULL-Werte wird zusätzlicher Speicherplatz benötigt, also 1 Byte pro Zeile. Bei Tabellen mit denselben Daten ist die Tabelle mit NULL-Werten im Feld größer als die Tabelle mit NOT NULL-Werten.

Drei: 1 NULL- und 1 ''-Daten:

mysql> Tabelle erstellen mytest(t1 varchar(10) NICHT NULL,t2 varchar(10) NICHT NULL STANDARD '',t3 varchar(10) NICHT NULL ,t4 varchar(10))engine=innodb charset = latin1 row_format=compact;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
mysql> einfügen in mytest(t1,t2) Werte('A','BB');
Abfrage OK, 1 Zeile betroffen, 1 Warnung (0,01 Sek.)

Die Schritte sind dieselben wie oben und das ibd-Ergebnis ist:

0000c070 73 75 70 72 65 6d 75 6d 00 02 01 01 00 00 10 ff |supremum........|
0000c080 ef 00 00 00 43 b9 03 00 00 00 02 4a 15 90 00 00 |....C......J...|
0000c090 01 c2 01 10 41 42 42 00 00 00 00 00 00 00 00 00 |....ABB.........|

Der Hauptunterschied zu den beiden oben genannten liegt in der Listen- und Spaltendaten variabler Länge.

Fazit: Die Spaltendateninformationen zeigen, dass NULL-Daten und ''-Daten keinen Speicherplatz belegen. Für die Informationen der Feldliste mit variabler Länge zeigt ein Vergleich, dass: ''-Daten zwar keinen Speicherplatz belegen müssen, aber dennoch ein Byte in der Feldliste mit variabler Länge belegen müssen <schließlich handelt es sich immer noch um einen ''-Wert>, und der NULL-Wert muss nicht " belegen, aber NULL hat ein zusätzliches Flag-Bit, daher gibt es eine Optimierungsanweisung: "Versuchen Sie, NOT NULL in der Datenbanktabelle festzulegen, wenn es auf NOT NULL festgelegt werden kann, es sei denn, NULL wird wirklich benötigt. “ wird hier bewiesen.

Die obigen Tests gelten alle für VARCHAR-Typen mit variabler Länge. Was ist mit CHAR?

CHAR-Test:

root@localhost: Test 10:33:35>Tabelle erstellen mytest(t1 char(10),t2 char(10),t3 char(10),t4 char(10))engine=innodb charset = latin1 row_format=compact; Abfrage OK, 0 Zeilen betroffen (0,16 Sek.)

root@localhost: Test 10:33:59>in mytest-Werte einfügen('a', 'bb', 'bb', 'ccc');
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

root@localhost: Test 10:34:09> in mytest-Werte einfügen ('a', 'ee', 'ee', 'fff');
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

root@localhost: Test 10:34:19> in mytest-Werte einfügen ('a', NULL, NULL, 'fff');
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

Öffnen Sie die von ibd generierte Datei:

0000c060 02 00 1b 69 6e 66 69 6d 75 6d 00 04 00 0b 00 00 |...unbestimmt......|
0000c070 73 75 70 72 65 6d 75 6d 00 00 00 10 00 41 00 00 |Supremum.....A..|
0000c080 00 0a f5 00 00 00 00 81 2d 07 80 00 00 00 32 01 |........-.....2.|
0000c090 10 61 20 20 20 20 20 20 20 20 20 20 62 62 20 20 20 |.a bb |
0000c0a0 20 20 20 20 20 62 62 20 20 20 20 20 20 20 20 20 63 | bb c|
0000c0b0 63 63 20 20 20 20 20 20 20 00 00 00 18 00 41 00 |cc .....A.|
0000c0c0 00 00 0a f5 01 00 00 00 81 2d 08 80 00 00 00 32 |.........-.....2|
0000c0d0 01 10 61 20 20 20 20 20 20 20 20 20 20 65 65 20 20 |..a ee |
0000c0e0 20 20 20 20 20 20 65 65 20 20 20 20 20 20 20 20 20 | ee |
0000c0f0 66 66 66 20 20 20 20 20 20 20 06 00 00 20 ff 70 |fff ... .p|
0000c100 00 00 00 0a f5 02 00 00 00 81 2d 09 80 00 00 00 |..........-.....|
0000c110 32 01 10 61 20 20 20 20 20 20 20 20 20 20 66 66 66 |2..a fff|
0000c120 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 00 | .........|

Im Vergleich zu varchar stellt sich Folgendes heraus: Es gibt weniger Feldlisten mit variabler Länge, für char ist jedoch eine feste Länge zum Speichern erforderlich, und wenn die feste Länge nicht gespeichert werden kann, wird es aufgefüllt. Beispiel: 20; und NULL-Werte müssen keinen Speicherplatz belegen.

Gemischt (varchar, char):

root@localhost: Test 11:21:48>Tabelle erstellen mytest(t1 int,t2 char(10),t3 varchar(10),t4 char(10))engine=innodb charset = latin1 row_format=compact;
Abfrage OK, 0 Zeilen betroffen (0,17 Sek.)

root@localhost: Test 11:21:50>in mytest-Werte einfügen (1, „a“, „b“, „c“);
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

root@localhost: Test 11:22:06> in mytest-Werte einfügen (11, „aa“, „bb“, „cc“);
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

Aus der obigen Tabellenstruktur können wir Folgendes ersehen:
1. Länge der Feldliste mit variabler Länge: 1
2. NULL-Flag: 1
3. Datensatzkopfinformationen: 5
4, Zeilen-ID: 6
5. Transaktions-ID: 6
6. Rollback-Zeiger: 7

IDB-Informationen:

0000c070 73 75 70 72 65 6d 75 6d 01 00 00 00 10 00 33 00 |Supreme…….3.| 
0000c080 00 00 0a f5 07 00 00 00 81 2d 1a 80 00 00 00 32 |.........-.....2|
0000c090 01 10 80 00 00 01 61 20 20 20 20 20 20 20 20 20 20 |......a |
0000c0a0 62 63 20 20 20 20 20 20 20 20 20 20 02 00 00 00 18 |bc .....|
0000c0b0 ff be 00 00 00 0a f5 08 00 00 00 81 2d 1b 80 00 |............-...|
0000c0c0 00 00 32 01 10 80 00 00 0b 61 61 20 20 20 20 20 |..2......aa |
0000c0d0 20 20 20 62 62 63 63 20 20 20 20 20 20 20 20 20 00 | bbcc .|

Aus den obigen Informationen können wir schließen, dass es dasselbe ist wie erwartet: Da es in der Tabelle nur ein varchar-Feld gibt, beträgt die Länge der Liste mit variabler Länge nur: 01
Achten Sie besonders auf die folgenden Informationen zur Datenspeicherung in jeder Spalte: Das Feld t1 ist vom Typ int und belegt 4 Bytes. Die erste Zeile: 80 00 00 01 steht für die Zahl 1; die zweite Zeile: 80 00 00 0b steht für die Zahl 11. [select hex(11) == B ], der Rest ist wie oben.

Oben finden Sie Beschreibungen des Einzelbyte-Zeichensatzes Latin1. Was ist mit dem Mehrbyte-Zeichensatz?

root@localhost: Test 11:52:10>Tabelle erstellen mytest(id int auto_increment, t2 varchar(10), t3 varchar(10), t4 char(10), Primärschlüssel(id))Engine=innodb Zeichensatz = utf8 Zeilenformat=kompakt;
Abfrage OK, 0 Zeilen betroffen (0,17 Sek.)

root@localhost: Test 11:52:11>Einfügen in mytest(t2,t3,t4) Werte('bb','bb','ccc');
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

root@localhost: Test 11:55:34>Einfügen in mytest(t2,t3,t4) Werte('wir','sie','unser');
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)

Die ibd-Informationen lauten wie folgt:

0000c070 73 75 70 72 65 6d 75 6d 0a 02 02 00 00 00 10 00 |Supreme……|
0000c080 28 80 00 00 01 00 00 00 81 2d 27 80 00 00 00 32 |(........-'....2|
0000c090 01 10 62 62 62 62 63 63 63 20 20 20 20 20 20 20 20 |..bbbbccc |
0000c0a0 0a 06 06 00 00 00 18 ff c7 80 00 00 02 00 00 00 |................|
0000c0b0 81 2d 28 80 00 00 00 32 01 10 e6 88 91 e4 bb ac |.-(....2........|
0000c0c0 e4 bb 96 e4 bb ac e6 88 91 e4 bb ac e7 9a 84 20 |............... |

Da die Tabelle einen Primärschlüssel hat, ist die ROWID (6 Bytes) weg.
Achten Sie besonders auf: Die Feldliste mit variabler Länge beträgt 3? Es gibt nur zwei Varchar-Spalten in der Tabelle. Der Test zeigt, dass unter der Bedingung eines Mehrbyte-Zeichensatzes der Typ char als Typ mit variabler Länge behandelt wird und es grundsätzlich keinen Unterschied bei der Speicherung ihrer Zeilen gibt. Daher beträgt die Liste mit variabler Länge 3, da es sich um den UTF-8-Zeichensatz handelt, der drei Bytes belegt. Ein chinesisches Schriftzeichen nimmt also 3 Byte Platz auf einer Seite ein („wir“: e6 88 91 e4 bb ac).
Informationen zu den Datenspalten:
Der Wert 1 der ID-Spalte sollte 80 00 00 01 sein. Warum wird hier 00 32 01 10 angezeigt, obwohl alle IDs 00 32 01 10 sind? Der Test ergab, dass die 4-Byte-Länge der ID durch 00 32 01 10 dargestellt wird, wenn es sich bei der ID um einen automatisch inkrementierten Primärschlüssel handelt. Andernfalls verwenden Sie zur Darstellung wie im vorherigen Beispiel „select HEX (X)“.

Zusammenfassung 2:
Die obigen Tests basieren alle auf dem COMPACT-Speicherformat. Unabhängig davon, ob es sich um varchar oder char handelt, belegen NULL-Werte keinen Speicherplatz. Es ist besonders wichtig zu beachten, dass die Datensatzkopfinformationen von Redumdant 6 feste Bytes erfordern. Unter der Bedingung eines Mehrbyte-Zeichensatzes gibt es grundsätzlich keinen Unterschied zwischen der Zeilenspeicherung von CHAR und VARCHAR.

Dies ist das Ende dieses Artikels über die MySQL Innodb-Speicherstruktur und die Speicherung von Nullwerten. Weitere Informationen zur MySQL Innodb-Speicherstruktur und zur Speicherung von Nullwerten finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Leistungsvergleichstest der beiden Tabellenspeicherstrukturen von MySQL, MyISAM und InnoDB
  • InnoDB-Typ MySql stellt Tabellenstruktur und Daten wieder her
  • Detaillierte Erläuterung des Index und der Speicherstruktur der MySQL InnoDB-Engine
  • Detaillierte Erläuterung der Datenseitenstruktur der InnoDB-Speicher-Engine von MySQL
  • Details zur MySQL InnoDB-Speicherstruktur

<<:  Skript zum schnellen Auflisten aller Hostnamen (Computernamen) im LAN unter Linux

>>:  Implementieren eines Webplayers mit JavaScript

Artikel empfehlen

20 JS-Abkürzungsfähigkeiten zur Verbesserung der Arbeitseffizienz

Inhaltsverzeichnis Wenn Sie mehrere Variablen gle...

Probleme bei der Installation von MySQL und mysql.sock unter Linux

Vor kurzem traten bei der Installation von Apache...

Mehrere Methoden zum Löschen von Floating (empfohlen)

1. Fügen Sie ein leeres Element desselben Typs hi...

Einige gängige CSS-Layouts (Zusammenfassung)

Zusammenfassung In diesem Artikel werden die folg...

HTML erstellt eine einfache und schöne Anmeldeseite

Schauen wir uns das zunächst einmal an. HTML Quel...

Zusammenfassung der React-Grundlagen

Inhaltsverzeichnis Vorwort Start React-Lebenszykl...

Grafisches Tutorial zur Installation und Konfiguration von MySQL 8.0.22 winx64

Das grafische Tutorial zur Installation und Konfi...

Optimierung der Web-Frontend-Leistung

Best Practices für die Web-Frontend-Optimierung: ...

Ein kurzer Vortrag über den Diff-Algorithmus in Vue

Inhaltsverzeichnis Überblick Virtueller Dom Prinz...

MYSQL Performance Analyzer EXPLAIN Anwendungsbeispielanalyse

Dieser Artikel veranschaulicht anhand eines Beisp...