Este artigo leva você a entender a estrutura de registro InnoDB do MySQL [Parte 2]

prefácio

O artigo anterior disse que o InnoDB tem formatos Compact, Redundant, Dynamice Compressed4de linha. Ele fala principalmente sobre Compacto formato de linha, que é composto de duas partes principais: informações adicionais registradas e dados reais gravados. Recomenda-se a leitura do artigo anterior e do artigo anterior .Se for importante Diga [ através do trem ] três vezes, não pule o capítulo. Hoje, entendemos principalmente os três formatos de linha restantes e o estouro de dados de linha

1. Formato de linha redundante

O formato de linha redundante é um formato de linha usado antes do MySQL 5.0, o que significa que é muito antigo, mas ainda quero mencioná-lo do ponto de vista do aprendizado e todos podem entendê-lo. O formato de linha redundante Como mostrado na figura:

insira a descrição da imagem aqui
Para um melhor aprendizado, criamos uma demo3tabela aqui e adicionamos dois dados

mysql> create table demo3( c1 varchar(10), c2 varchar(10) not null, c3 char(10), c4 varchar(10), c5 varchar(1024)) charset=ascii row_format=Redundant;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into demo3 values('aaaaa','bbbb','ccc','dd','e');
Query OK, 1 row affected (0.00 sec)

mysql> insert into demo3 values('eeeee','ffff',null,null,'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdeefghijklmnopqrstuvwxyz');
Query OK, 1 row affected (0.00 sec)

Os registros na tabela agora se parecem com isso

mysql> select * from demo3;
+-------+------+------+------+------------------------------------------------------------------------------------------------------------------------------------+
| c1    | c2   | c3   | c4   | c5                                                                                                                                 |
+-------+------+------+------+------------------------------------------------------------------------------------------------------------------------------------+
| aaaaa | bbbb | ccc  | dd   | e                                                                                                                                  |
| eeeee | ffff | NULL | NULL | abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz |
+-------+------+------+------+------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

Vamos dar uma olhada nas diferenças no formato de linha redundante de vários aspectos.

1.1 Lista de compensação de comprimento de campo

CompactO início do formato de linha é uma lista de comprimento de campo de comprimento variável e Redundanto início do formato de linha é uma lista de deslocamento de comprimento de campo, que é diferente da lista de comprimento de campo de comprimento variável de duas maneiras:

  • Não há 变长duas palavras, ou seja, o formato de linha redundante armazenará as informações de comprimento de todas as colunas (incluindo colunas ocultas) no registro em ordem inversa à lista de deslocamento de comprimento de campo
  • Existem mais duas 偏移palavras, o que significa que o método de cálculo do comprimento é diferente do formato de linha Compact, que não é tão intuitivo, pois usa a diferença entre números adjacentes para calcular o comprimento de cada coluna.

Por exemplo, a primeira linha de dados, vamos tentar analisá-la:

O comprimento da primeira coluna row_idé de 6 bytes, ou seja, o comprimento da 0x06
segunda coluna trx_idé de 6 bytes, totalizando 12 bytes, ou seja, o comprimento da 0x0c
terceira coluna roll_pointeré de 7 bytes, totalizando 19 bytes, também Isso ou seja, o comprimento da 0x13
quarta coluna C1é de 5 bytes, um total de 24 bytes, ou seja, o comprimento da 0x18
quinta coluna C2é de 4 bytes, um total de 28 bytes, ou seja, o comprimento 0x1c
da sexta coluna C3é de 10 bytes, Um total de 38 bytes, ou seja, o comprimento 0x26
da sétima coluna C4é de 2 bytes, um total de 40 bytes, ou seja, o comprimento 0x28
da oitava coluna C5é de 1 byte, um total de 41 bytes, ou seja0x29

O efeito da descarga de ordem inversa é: 29 28 26 1c 18 13 0c 06, preencha os dados conforme mostrado na figura

insira a descrição da imagem aqui
Abrimos diretamente demo3.ibdo arquivo para visualizar

insira a descrição da imagem aqui

1.2 Informações do cabeçalho do registro

As informações do cabeçalho do registro no formato de linha redundante consistem em 6 bytes e 48 bits binários. Os significados desses bits binários são os seguintes:

nome tamanho (unidade: bit) descrever
Bit reservado 1 1 não usado
Reservado 2 1 não usado
delete_mask 1 Marque se o registro foi deletado
min_rec_mask 1 Esta marca será adicionada ao menor registro em cada nó não folha da árvore B+
n_propriedade 4 Indica o número de registros pertencentes ao registro atual
heap_no 13 Indica as informações de posição do registro atual na pilha de registros
n_campo 10 Indica o número de colunas no registro
1byte_offs_flag 1 Se o deslocamento correspondente a cada coluna na lista de deslocamento do comprimento do campo de tag é representado por 1 byte ou 2 bytes
próximo_registro 16 Indica a posição relativa do próximo registro

A primeira linha de informações do cabeçalho do registro é:00 00 10 11 00 ca

insira a descrição da imagem aquiVamos converter o registro acima de hexadecimal para binário e tentar analisá-lo

00000000 00000000 00010000 00010001 00000000 11001010

De acordo com esses dados binários, as seguintes informações podem ser obtidas dividindo os dados de acordo com a estrutura do cabeçalho do registro

Bit reservado 1: 0
Bit reservado 2: 0
delete_mask: 0
min_rec_mask: 0
n_owned: 0000
heap_no: 00000000 00010 (2)
n_field: 000 0001000 (8)
1byte_offs_flag: 1 (1)
next_record: 00000000 11001010 ( 202)

Em comparação com as informações do cabeçalho do registro no formato de linha Compacto, há duas diferenças:

  • O formato de linha redundante possui mais dois atributos: n_field e 1byte_offs_flag;
  • O formato de linha redundante não possui o atributo record_type.

1.4 Como escolher o valor de 1byte_offs_flag

Dissemos anteriormente que o deslocamento correspondente a cada coluna pode ocupar 1 byte ou 2 bytes para armazenamento, então quando usar 1 byte e quando usar 2 bytes? Na verdade, é julgado de acordo com o tamanho total dos dados reais registrados no formato de linha redundante:

  • Quando o número de bytes ocupados pelos dados reais gravados for menor ou igual a 127 (hexadecimal 0x7f, binário 01111111), o deslocamento correspondente a cada coluna ocupa 1 byte

  • Quando o número de bytes ocupados pelos dados reais registrados for maior que 127, mas não maior que 32767 (hexadecimal 0x7fff, binário 01111111111111111), o deslocamento correspondente a cada coluna ocupa 2 bytes

  • Quando os dados reais do registro são maiores que 32767, o registro neste momento foi armazenado na página de estouro, e apenas os primeiros 768 bytes e o endereço da página de estouro de 20 bytes são reservados nesta página (é claro, nesses 20 bytes Algumas outras informações também são registradas). Como a lista de deslocamento do comprimento do campo só precisa registrar o deslocamento de cada coluna nesta página, é suficiente que cada coluna use 2 bytes para armazenar o deslocamento.

Para saber se o deslocamento de cada coluna é representado por 1 byte ou 2 bytes ao analisar registros, o formato de linha redundante coloca deliberadamente um atributo chamado 1byte_offs_flag nas informações do cabeçalho do registro:

  • Quando seu valor é 1, indica que 1 byte é usado para armazenamento
  • Quando seu valor é 0, indica que 2 bytes são usados ​​para armazenamento

1.5 Tratamento de valores NULL no formato de linha redundante

Como o formato de linha redundante não possui uma lista de valores NULL, o formato de linha redundante faz algum processamento especial nos deslocamentos correspondentes a cada coluna na lista de deslocamento de comprimento de campo - o primeiro bit do valor de deslocamento correspondente à coluna Como base pois se for NULL, esse bit também pode ser chamado de bit NULL. Ou seja, ao analisar uma coluna de um registro, verifique primeiro se o bit NULL do deslocamento correspondente à coluna é 1, se for 1, o valor da coluna é NULL, caso contrário, não é NULL.

Isso também explica porque, desde que os dados reais registrados acima sejam maiores que 127 (hexadecimal 0x7f, binário 01111111), 2 bytes são usados ​​para representar o deslocamento correspondente a uma coluna, principalmente o primeiro bit É o chamado bit NULL, usado para marcar se o valor da coluna é NULL.

Mas há outro ponto a observar, para uma coluna com um valor NULL, se o tipo da coluna é um tipo de comprimento fixo determina o método de armazenamento real do valor NULL:

  • Se o campo que armazena o valor NULL for do tipo de comprimento fixo, como o tipo de dados CHAR(M), o valor NULL também ocupará a parte de dados reais do registro e os dados correspondentes a esse campo serão preenchidos com 0x00 bytes .
  • Se o campo que armazena o valor NULL for do tipo de dados de comprimento variável, nenhum espaço de armazenamento será ocupado nos dados reais do registro.

Além dos pontos acima, o formato de linha redundante e o formato de linha compacta são aproximadamente os mesmos

Vamos tentar analisar o segundo dado (o número de bytes ocupados pelos dados reais é maior que 127):

O comprimento da primeira coluna row_idé de 6 bytes, ou seja, o comprimento da 0x00 0x06
segunda coluna trx_idé de 6 bytes, totalizando 12 bytes, ou seja, o comprimento da 0x00 0x0c
terceira coluna roll_pointeré de 7 bytes, totalizando 19 bytes, também Isso ou seja, o comprimento da 0x00 0x13
quarta coluna C1é de 5 bytes, um total de 24 bytes, ou seja, o comprimento da 0x00 0x18
quinta coluna C2é de 4 bytes, um total de 28 bytes, ou seja, o comprimento 0x00 0x1c
da sexta coluna C3é de 10 bytes, Um total de 38 bytes, ou seja 0x00 0x26, mas o valor é NULL, 最高位标识1depois disso, o valor 0x80 0x26
da sétima coluna C4é NULL, um total de 38 bytes, ou seja, o comprimento da 0x80 0x26
oitava coluna C5é de 130 bytes, um total de 168 Festival de personagens, ou seja0x00 0xa8

Abrimos diretamente o arquivo demo3.ibd para ver se está correto:

insira a descrição da imagem aquiAlém dos pontos acima, o formato de linha redundante e o formato de linha compacta são praticamente os mesmos.

1.6 Formato de armazenamento da coluna CHAR(M)

Sabemos que o formato de linha compacta é bastante problemático ao armazenar dados em colunas do tipo CHAR(M). Ele é dividido em conjuntos de caracteres de comprimento variável e conjuntos de caracteres de comprimento fixo, mas é muito simples no formato de linha redundante, independentemente os caracteres usados ​​na coluna. Qual é o conjunto, desde que o tipo CHAR(M) seja usado, o espaço de dados real ocupado é o produto do número máximo de bytes exigidos pelo conjunto de caracteres para representar um caractere e M. Por exemplo, o espaço de dados real ocupado por uma coluna do tipo CHAR(10) usando o conjunto de caracteres utf8 é sempre de 30 bytes, e o espaço de dados real ocupado por uma coluna do tipo CHAR(10) usando o conjunto de caracteres gbk é sempre de 20 bytes. Pode-se ver a partir disso que a coluna do tipo CHAR(M) usando o formato de linha redundante não gerará fragmentação.

2. Estouro de dados de linha

2.1 O máximo de dados que VARCHAR(M) pode armazenar

Sabemos que uma coluna do tipo VARCHAR(M) pode ocupar até 65535 bytes. Entre eles, M representa o número máximo de caracteres armazenados neste tipo. Se usarmos o conjunto de caracteres ASCII, um caractere representa um byte. Vamos ver se VARCHAR(65535) está disponível

mysql> create table demo4 (c varchar(65535)) charset=ascii row_format=compact;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

Pode ser visto na mensagem de erro que o MySQL tem um limite no espaço máximo de armazenamento ocupado por um registro. Exceto para colunas do tipo BLOB ou TEXT, os bytes ocupados por todas as outras colunas (excluindo colunas ocultas e informações de cabeçalho de registro) O total comprimento não pode exceder 65535 bytes. Portanto, o servidor MySQL sugere que alteremos o tipo de armazenamento para o tipo TEXT ou BLOB. Além dos dados da própria coluna, esses 65535 bytes também incluem alguns outros dados (sobrecarga de armazenamento). Por exemplo, para armazenar uma coluna do tipo VARCHAR(M), na verdade precisamos ocupar 3 partes do espaço de armazenamento:

  • dados reais
  • Os dados reais ocupam o comprimento do byte (podem ocupar dois bits)
  • Identificação do valor NULL, se a coluna não tiver o atributo NOT NULL (um bit), então apenas 65532 bytes de dados podem ser armazenados no máximo
mysql> create table demo4 (c varchar(65532)) charset=ascii row_format=compact;
Query OK, 0 rows affected (0.06 sec)

Se a coluna do tipo VARCHAR(M) não usar o conjunto de caracteres ASCII, o valor máximo de M dependerá do número máximo de bytes exigidos pelo conjunto de caracteres para representar um caractere. No caso em que o valor da coluna pode ser NULL, o conjunto de caracteres gbk indica que um caractere requer no máximo 2 bytes; nesse conjunto de caracteres, o valor máximo de M é 32766 (ou seja: 65532/2) , ou seja, pode armazenar até 32766 caracteres; o conjunto de caracteres utf8 significa que um caractere precisa de até 3 bytes; portanto, nesse conjunto de caracteres, o valor máximo de M é 21844, o que significa que ele pode armazenar até 21844 ( ou seja: 65532/3) caractere.

2.2 Estouro causado por excesso de dados no registro

Vamos fazer um teste com asciiuma demo4tabela de conjunto de caracteres e inserir um dado:

mysql> insert into demo4 values(repeat('a',65532));
Query OK, 1 row affected (0.02 sec)

Dica:
REPEAT('a', 65532) é uma chamada de função, que significa gerar uma string que repete o caractere 'a' 65532 vezes

Como mencionado anteriormente, a unidade básica de interação entre disco e memória no MySQL é a página, ou seja, o MySQL usa a página como unidade básica para gerenciar o espaço de armazenamento, e nossos registros serão alocados para uma determinada página para armazenamento. O tamanho de uma página é geralmente 16 KB, que é 16384 bytes, e um VARCHAR(M)tipo de coluna pode armazenar até 65532 bytes, o que pode causar uma situação embaraçosa em que uma página não pode armazenar um registro

Nos formatos de linha Compacto e Reduntante, para uma coluna que ocupa um grande espaço de armazenamento, apenas uma parte dos dados da coluna será armazenada nos dados reais do registro, e os dados restantes serão dispersos e armazenados em vários outros páginas e, em seguida, os dados reais do registro O local de dados usa 20 bytes para armazenar os endereços que apontam para essas páginas (claro, esses 20 bytes também incluem o número de bytes ocupados pelos dados espalhados em outras páginas), para que o pode ser encontrada a página onde os dados restantes estão localizados, como mostrado na figura:

insira a descrição da imagem aqui
Como pode ser visto na figura, para os formatos de linha Compact e Reduntant, se houver muitos dados em uma coluna, apenas os primeiros 768 bytes de dados na coluna e um ponteiro para outras colunas serão armazenados nos dados reais de este registro. O endereço da página e, em seguida, armazenar os dados restantes em outras páginas. Esse processo também é chamado de estouro de página, e as páginas que armazenam mais de 768 bytes também são chamadas de páginas de estouro.

Finalmente, deve-se notar que não apenas colunas do tipo VARCHAR(M), mas também colunas de outros tipos TEXT e BLOB irão estourar ao armazenar muitos dados.

Três, o ponto crítico de estouro de linha

Qual é o ponto crítico onde ocorre o estouro de linha? Em outras palavras, estouro de linha ocorre quando a coluna armazena quantos bytes de dados?

O MySQL estipula que pelo menos duas linhas de registros devem ser armazenadas em uma página. Além de armazenar nossos registros, cada página também precisa armazenar algumas informações adicionais. As informações extras confusas precisam adicionar até 132 bytes de espaço (agora você só precisa saber este número. ok), o restante do espaço pode ser usado para armazenar registros.

A informação adicional necessária para cada registro é de 27 bytes.

  • 2 bytes são usados ​​para armazenar o comprimento dos dados reais
  • 1 byte é usado para armazenar se a coluna é um valor NULL
  • 5 bytes de informações de cabeçalho
  • 6 bytes para a coluna DB_ROW_ID
  • 6 bytes para a coluna DB_TRX_ID
  • 7 bytes para a coluna DB_ROLL_PTR

Assumindo que o número de bytes de dados armazenados em uma coluna é n, o MySQL estipula que, se a coluna não estourar, ela precisa satisfazer a seguinte fórmula:

132 + 2×(27 + n) < 16384

Resolver esta fórmula leva à solução: n <8099. Ou seja, se os dados armazenados em uma coluna forem menores que 8099 bytes, a coluna não se tornará uma coluna de estouro, caso contrário, a coluna precisará se tornar uma coluna de estouro. No entanto, a conclusão de 8099 bytes é apenas para uma demo4tabela com apenas uma coluna. Se houver várias colunas na tabela, a fórmula e a conclusão acima precisam ser alteradas, então o ponto é: você não precisa prestar atenção isso crítico Qual é o ponto, apenas saiba que se os dados armazenados em uma coluna do nosso registro ocuparem muitos bytes, a coluna pode se tornar uma coluna de estouro.

Formato de linha quatro, DINÂMICO e COMPRIMIDO

O seguinte apresentará os outros dois formatos de linha Dynamice Compressedo formato de linha. A versão do MySQL que estou usando agora é 8.0 e seu formato de linha padrão é Dinâmico

mysql> show variables like '%innodb_default_row_format%';
+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+
1 row in set (0.04 sec)

mysql> set persist innodb_default_row_format = 'dynamic';
Query OK, 0 rows affected (0.01 sec)

Esses dois formatos de linha são semelhantes ao formato de linha Compact, mas são um pouco diferentes ao lidar com dados de estouro de linha. Eles não armazenarão os primeiros 768 bytes dos dados reais do campo nos dados reais do registro, mas armazenarão todos os bytes Eles são todos armazenados em outras páginas, e apenas os endereços de outras páginas são armazenados nos dados reais registrados.

A diferença entre o formato de linha compactado e dinâmico é que o formato de linha compactado usa um algoritmo de compactação para compactar a página para economizar espaço.

Resumir

Esses dois artigos tem muito conhecimento teórico, haha, mas felizmente não são muito usados ​​no trabalho. É bom que todos conheçam esses termos, pois na explicação do MVCC mais adiante, também usaremos alguns termos profissionais neste artigo . InnoDB define 4 formatos de linha, e a estrutura de registro de cada formato de linha é diferente. Ao mesmo tempo, também aprendemos sobre os métodos de armazenamento de tipos de dados de comprimento fixo e variável na estrutura de registro e estouro de linha. Vamos lá. concluir

  • A página é a unidade básica de interação de disco e memória no MySQL e também a unidade básica do MySQL para gerenciar o espaço de armazenamento.

  • InnoDB atualmente define 4 formatos de linha:

    • Formato de linha COMPACTO:
      insira a descrição da imagem aqui
    • Formato de linha REDUNDANTE:

    insira a descrição da imagem aqui

    • Formatos de linha DYNAMIC e COMPRESSED:

      Os formatos de linha Dinâmico e Compactado são semelhantes ao formato de linha COMPACT, e são um pouco diferentes ao lidar com dados de estouro de linha. Eles não armazenam os primeiros 768 bytes dos dados reais do campo nos dados reais do registro, mas armazenam todos os bytes. Para outras páginas, apenas armazene o endereço de outras páginas nos dados reais do registro

  • Formato de linha COMPACT Para colunas do tipo CHAR(M), quando a coluna usa um conjunto de caracteres de comprimento fixo, o número de bytes ocupados pela coluna não será adicionado à lista de comprimento de campo de comprimento variável e, se o comprimento variável conjunto de caracteres for usado, o número de bytes ocupados pela coluna também será adicionado à lista de comprimento de campo de comprimento variável.

  • No caso em que o valor da coluna pode ser NULL, o valor máximo de M no conjunto de caracteres gbk é 32766 e o ​​valor máximo de M no conjunto de caracteres utf8 é 21844. Isso tudo no caso de apenas um campo na tabela. Certifique-se de lembrar que o comprimento total de bytes ocupados por todas as colunas em uma linha (excluindo colunas ocultas e informações de cabeçalho de registro) não pode exceder 65535 bytes!

  • Quando há muitos dados no registro e não cabem na página atual, os dados excedentes serão armazenados em outras páginas, fenômeno chamado estouro de linha. Nos formatos de linha Compacto e Redundante, para colunas que ocupam um grande espaço de armazenamento, apenas uma parte dos dados da coluna será armazenada nos dados reais gravados, e os dados restantes serão dispersos e armazenados em várias outras páginas, e então os 20 bytes de dados reais registrados são usados ​​para armazenar endereços que apontam para essas páginas.

  • O ponto crítico do estouro de linha: se os dados armazenados em uma coluna forem menores que 8.099 bytes, a coluna não se tornará uma coluna de estouro, caso contrário, a coluna precisa ser uma coluna de estouro. No entanto, a conclusão de 8099 bytes é apenas para uma tabela com apenas uma coluna. Se houver várias colunas na tabela, a conclusão será inconsistente, então a questão é: você não precisa prestar atenção em qual é o ponto crítico ou seja, apenas saiba que se quando os dados armazenados em uma coluna de um registro ocuparem um número muito alto de bytes, a coluna pode se tornar uma coluna de estouro.

  • As colunas do tipo CHAR(M) do conjunto de caracteres de comprimento variável requerem pelo menos M bytes, enquanto VARCHAR(M) não possui esse requisito. Por exemplo, para uma coluna CHAR(10) usando o conjunto de caracteres utf8, o comprimento dos dados armazenados na coluna varia de 10 a 30 bytes. Mesmo se armazenarmos uma string vazia nesta coluna, ela ocupará 10 bytes. Isso ocorre porque o comprimento de bytes do valor atualizado no futuro é maior que o comprimento de bytes do valor original e menor que 10 bytes. O registro é atualizado diretamente em vez de realocar um novo espaço de registro no espaço de armazenamento, fazendo com que o espaço de registro original se torne a chamada fragmentação

Quando terminei de aprender essa parte do conhecimento, admirei a profundidade da pesquisa do autor.Embora os pontos de conhecimento sejam muitos, difíceis e complicados, a forma como o autor combina imagens e textos nos permite entendê-lo bem.

Até agora, o estudo de hoje acabou, espero que você se torne um eu indestrutível
~~~

Você não pode ligar os pontos olhando para frente; você só pode conectá-los olhando para trás. Portanto, você precisa confiar que os pontos de alguma forma se conectarão em seu futuro. Você precisa confiar em algo - seu instinto, destino, vida, karma, seja o que for. Essa abordagem nunca me decepcionou e fez toda a diferença na minha vida

Se meu conteúdo for útil para você, por favor 点赞, criar não é fácil, o apoio de todos é a 评论motivação 收藏para eu perseverar

insira a descrição da imagem aqui

Acho que você gosta

Origin blog.csdn.net/liang921119/article/details/130551482
Recomendado
Clasificación