UPDATE: tl; dr: O problema foi que o MySQL usa TMPDIR
ao criar índices. E o meu TMPDIR
foi ficar sem espaço em disco.
Q original:
Estou tentando adicionar um índice a uma tabela do InnoDB e obtendo um table is full error
. Eu tenho espaço em disco suficiente e a configuração do MySQL possui um arquivo por tabela = 1. Os dados da tabela são de 85 GB e presumo que o índice esteja entre 20 e 30 GB e tenho muito mais espaço em disco do que isso. Também estou usando ext3, então não sinto nenhum problema com o limite de tamanho do arquivo do ponto de vista do SO.
O erro registrado é assim:
140616 13:04:33 InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full
O que está causando isso e como posso resolver?
A tabela de criação:
`CREATE TABLE `my_table` (
`uid_from` bigint(11) NOT NULL,
`uid_to` bigint(11) NOT NULL,
`counter` int(11) NOT NULL,
`updated` date NOT NULL,
PRIMARY KEY (`uid_to`,`uid_from`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8`
Como os dados são 87,4 GB e eu estimo que haja cerca de 1,5B linhas.
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Variable_name Value
tmpdir /tmp
[root@web ~]# df -h /tmp
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 40G 24G 14G 64% /
Respostas:
Por favor, não se deixe enganar pela mensagem de erro
The table 'my_table' is full
. Esse cenário raro não tem absolutamente nada a ver com espaço em disco. Esta condição de tabela completa tem a ver com o encanamento interno do InnoDB.Primeiro, dê uma olhada neste diagrama da arquitetura InnoDB
Observe que o espaço de tabela do sistema (o arquivo ibdata) possui apenas 128 segmentos de reversão e 1023 slots de reversão por segmento de reversão. Isso limita o tamanho da capacidade de reversão de uma transação. Em outras palavras, se um único segmento de reversão precisar de mais de 1023 slots para suportar uma transação, a transação atingirá essa
table is full
condição.Pense no restaurante Red Lobster, em Nova Jersey . Pode ter capacidade para 200 pessoas. Se o restaurante estiver cheio, uma fila de pessoas poderá sair para esperar. Se as pessoas na fila ficarem impacientes, elas poderão sair porque o restaurante está cheio. Obviamente, a solução não seria aumentar Nova Jersey (ou obter mais espaço em disco). A solução seria aumentar o restaurante Red Lobster. Dessa forma, você pode aumentar a capacidade de assentos para, digamos, 240. Mesmo assim, uma fila pode se formar do lado de fora se mais de 240 pessoas decidirem vir para a Red Lobster.
Só para dar um exemplo, eu tinha um cliente com 2TB de espaço de tabela do sistema e innodb_file_per_table foi desativado. (346G para ibdata1, a redefinição para ibdata2). Eu executei esta consulta
Em seguida, subtraí InnoDBDataIndexSpace da soma dos tamanhos de arquivo para ibdata1 e ibdata2. Eu tenho duas coisas que me chocaram
Table is Full
condiçãoIsso significa que os 106 GB estavam sendo usados para o encanamento interno do InnoDB. O cliente estava usando ext3 no momento.
A solução para mim foi adicionar ibdata3. Eu discuti isso no meu post antigo Como resolver "A tabela ... está cheia" com "innodb_file_per_table"?
Eu discuti isso em outros posts também
Mar 31, 2014
: o diretório mysql cresce para 246G após uma consulta, que falhou devido à tabela estar cheiaNov 25, 2011
: ERRO 1114 (HY000) na linha 6308 no arquivo e a tabela user_analysis está cheiaLembre-se de que essa condição pode ocorrer mesmo se innodb_file_per_table estiver ativado. Como? Rollbacks e Undo Logs são a fonte de picos não controlados e o crescimento do ibdata1 .
SUA PERGUNTA REAL
Como você está adicionando um índice a uma tabela e obtendo
Table is Full
, a tabela deve ser enorme e não pode caber em um único segmento de reversão. Você deve fazer o seguinte:PASSO 01
Coloque os dados em um arquivo de despejo
PASSO 02
Entre no MySQL e execute este
PASSO 03
Carregue a tabela com o índice adicional com os dados
Isso é tudo.
Veja, o problema é que o ALTER TABLE tentará injetar todas as linhas da sua enorme tabela como uma única transação. Usar o mysqldump irá inserir os dados na tabela (agora com um novo índice) milhares de linhas por vez, nem todas as linhas em uma única transação.
Não se preocupe.
what if this doesn't work?
A tabela original será nomeadamytable_old
em caso de algo. pode servir como um backup. Você pode descartar o backup quando souber que a nova tabela funciona para você.De uma chance !!!
ATUALIZAÇÃO 16/06/2014 - 11:13
Se você está preocupado com o despejo de dados maior, basta compactá-lo.
Você pode executar as mesmas etapas, mas da seguinte maneira
PASSO 01
Coloque os dados em um arquivo de despejo
PASSO 02
Entre no MySQL e execute este
PASSO 03
Carregue a tabela com o índice adicional com os dados
ou
ATUALIZAÇÃO 16/06/2014 - 12:55
Acabei de pensar em outro aspecto em relação a esta questão.
Como você está executando DDL e não DML, é possível que isso não seja o encanamento interno do InnoDB. Como o DDL não pode reverter para o InnoDB , o problema deve ser o encanamento externo. Onde esse encanamento externo está entupido? Eu suspeito que a pasta temporária para o sistema operacional. Por quê?
Veja o
disk quota exceeded
? Onde essa cota de disco está sendo imposta?Execute esta consulta
Você disse que é
/var/lib/mysqltmp
Agora, execute isso no sistema operacional
Algo me diz que o espaço para
/var/lib/mysqltmp
estava se esgotando Afinal, você só tem 14G de graça. Aos olhos do DDL (para criar o índice), ocorreu uma reversão, não no arquivo ibdata1, mas notmpdir
local. Se/var/lib/mysqltmp
não estiver montado em nenhum lugar, os dados temporários serão gravados na partição raiz. Se/var/lib/mysqltmp
estiver montado em algum lugar, essa montagem será preenchida com dados de linha. Em ambos os casos, não há espaço suficiente para concluir o DDL.Você tem duas opções aqui
OPÇÃO 1
Você também pode criar um disco grande (talvez com mais de 100 GB) e montar
/var/lib/mysqltmp
nesse disco grande.OPÇÃO 2
Minhas sugestões em três etapas ainda devem funcionar, mesmo com o espaço em disco limitado que você possui
COMENTÁRIO
É uma pena a mensagem de erro que você postou diz
Isso significa que o sistema operacional está bem. Também não existe nenhum número de erro associado a essa situação.
Há outra coisa que você deve saber. A documentação do MySQL diz que a criação rápida de índice para o InnoDB ainda vai para o disco :
ATUALIZAÇÃO 16/06/2014 - 13:58 EDT
Certifique-se de
/mnt/cbsvolume1/var/lib/mysql
ter 100G ou mais grátisfonte