Vyprávění o prapodivné chybě InnoDB, kterou mě MySQL zase jednou dostalo; vysvětlění, proč tomu tak je a nakonec uspokojivé řešení problému.
Na jednom nejmenovaném projektu, který už brzy zveřejním, používám tabulky InnoDB. Aplikace každou hodinu updatuje data z externích zdrojů. Dnes se mi mailbox zaplnil zprávami, že update skončil chybou databáze
#1114 - The table '#sql-439_1a99f' is full
Začal jsem zjišťovat, co je to za blbost, proč by měla být tabulka plná, a v prvním zápalu paniky jsem dokonce začal zjišťovat, jestli je na disku dost místa. Nebudu vás dále napínat. Pokud vám MySQL také hlásí tuto chybu, a počítám že ano, protože jste se sem na 90% dostali zadáním InnoDb: Table is full do Googlu :-), tak tady je řešení:
Vysvětlení
V InnoDB nejsou data uložena v jednotlivých souborech po tabulkách, jako je to v případě MyISAM, ale v data souboru (jednom nebo více), který je společný nejen pro všechny InnoDB tabulky, ale i pro všechny databáze v rámci jednoho serveru.
V té části konfigurace MySQL, která je věnována InnoDB najdete defaultně zcela nesmyslnou konfiguraci:
innodb_data_file_path = ibdata1:10M:autoextend:max:128M
která doslova říká: bude jeden datový soubor ibdata1 o základní velikosti 10 MB. Pokud bude tato velikost překročena, bude se automaticky rozšiřovat, ale maximálně na 128 MB. Toto je výchozí konfigurace InnoDB v Debianu i v Gentoo. Nevím jak je to v jiných systémech, ale asi to bude podobné. Nechápu proč. 128 MB je nic a každý na tento limit dříve nebo později narazí a to možná v době, kdy se mu to bude nejméně hodit.
Řešení
Stačí tuto hodnotu maximální velikosti zvýšit třeba na 2 GB
innodb_data_file_path = ibdata1:10M:autoextend:max:2G
a nebo omezení velikosti datového souboru úplně odstranit
innodb_data_file_path = ibdata1:10M:autoextend
restartovat MySQL server a je pokoj.
Díky za tip 😉
InnoDB lze nastavit tak, aby každá tabulka byla v samostatném souboru, podobně jako to dělá MyISAM (s tím rozdílem, že MyISAM ještě ukládá zvlášť data a indexy, InnoDB dává vše do jednoho souboru). Dělá se to pomocí konfigurační direktivy
innodb_file_per_table
, více třeba na Using Per-Table TablespacesAno, treba pouzit direktivu innodb_file_per_table, aby neboli vsetky InnoDb v jednom subore ibdata1, ale v samostatnych. Napisal som o tom aj blog: https://www.itsoft.sk/preco-sa-neuvolni-miesto-na-disku-po-zmazani-mysql-tabulky/