Aparte de mis atribuciones regulares, tambien soy el DBA (administrador de base de datos) ad honorem y ultimamente me he dedicado a correguir errores y resolver problemas de MySQL. Todo empezo con el problema que detallo a continuacion:
Entre todas nuestras bases de datos existe una en particular que maneja un promedio de 40k transacciones diarias. Esta base de datos la cual corre en MySQL tiene una tabla la cual ya rebaso los 21 millones de registros, lo que la hacen tener los 4 GB de informacion.
Por su tamaño esta tabla MyISAM mostro el error The table is full, el cual al principio nos hizo pensar que podria ser limitaciones del kernel 2.4.x o del sistema de archivos ext2 (si, es un Red Hat Linux 9).
Limite de 4GB de MySQL
El error de MySQL, the table is full es un mensaje que se despliega cuando una tabla alcanza los 4GB de tamaño, a decir verdad se subestima el impacto, ya que son muy pocas las aplicaciones que pueden sobrepasar esta cantidad de datos. Pero cuando ya tenemos nuestros servicios consolidados y nuestro servidor de bases de datos MySQL deja de funcionar, representa un gran problema.
Es aconsejable realizar un buen analisis y diseño de nuestra de base de datos para que no ocurra esto. Sin embargo, a veces es dificil imaginar que una tabla pueda contener 21 millones de registros en dos años.
Las tablas InnoDB no tienen esta limitacion ya que su modelo de almacenamiento es completamente diferente. En una tabla MyISAM dinamica o de filas con longitud variable, el archivo de indice de la tabla (nombre_tabla.MYI) almacena utilizando filas con punteros de 32 bits dentro del archivo de datos (nombre_tabla.MYI). Esto tiene un limite de 4 GB de espacio.
Recordemos que la mayoria de computadoras son de 32bits ya que las tecnologias de 64 bits como el Opteron de AMD tambien tienen soporte para 32bits.
Solucionando el problema de la tabla esta llena
La solucion para the table is full no es muy dicil, tan solo basta con correr el comando ALTER TABLE, pero si puede llevar un tiempo considerable. Veamos como ejemplo la tabla de creatura de MaNGOS:
mysql> describe creature;
+-----------------+-----------------------+------+-----+---------+----------------+
| Field          | Type                 | Null | Key | Default | Extra         |
+-----------------+-----------------------+------+-----+---------+----------------+
| guid           | int(10) unsigned     | NO  | PRI | NULL   | auto_increment |
| id             | mediumint(8) unsigned | NO  | MUL | 0      |               |
| map            | smallint(5) unsigned | NO  | MUL | 0      |               |
| spawnMask      | tinyint(3) unsigned  | NO  |    | 1      |               |
| modelid        | mediumint(8) unsigned | NO  |    | 0      |               |
| equipment_id   | mediumint(9)         | NO  |    | 0      |               |
| position_x     | float                | NO  |    | 0      |               |
| position_y     | float                | NO  |    | 0      |               |
| position_z     | float                | NO  |    | 0      |               |
| orientation    | float                | NO  |    | 0      |               |
| spawntimesecs  | int(10) unsigned     | NO  |    | 120    |               |
| spawndist      | float                | NO  |    | 5      |               |
| currentwaypoint | mediumint(8) unsigned | NOÂ Â |Â Â Â Â | 0Â Â Â Â Â Â |Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
| curhealth      | int(10) unsigned     | NO  |    | 1      |               |
| curmana        | int(10) unsigned     | NO  |    | 0      |               |
| DeathState     | tinyint(3) unsigned  | NO  |    | 0      |               |
| MovementType   | tinyint(3) unsigned  | NO  |    | 0      |               |
+-----------------+-----------------------+------+-----+---------+----------------+
17 rows in set (0.02 sec)
Para encontrar el limite del tamaño de la tabla, usamos el comando SHOW TABLE STATUS. Y Observe que Max_data_length es 4 GB.
mysql> SHOW TABLE STATUS LIKE 'creature'G; *************************** 1. row ***************************           Name: creature         Engine: MyISAM        Version: 10     Row_format: Dynamic           Rows: 95094  Avg_row_length: 46    Data_length: 4382696 Max_data_length: 281474976710655   Index_length: 2628608      Data_free: 0  Auto_increment: 106039    Create_time: 2008-09-19 09:54:05    Update_time: 2008-09-19 10:31:08     Check_time: 2008-09-19 10:31:09      Collation: utf8_general_ci       Checksum: NULL  Create_options: row_format=DYNAMIC        Comment: Creature System 1 row in set (0.00 sec) ERROR: No query specified mysql>
Vamos a arreglar esto, tecleando:
mysql> ALTER TABLE creature MAX_ROWS = 200000000000 AVG_ROW_LENGTH = 50; Query OK, 0 rows affected (0,03 segundos)
Ahora si volvemos a ejecutar el comando SHOW TABLE STATUS LIKE ‘creature’G; podemos ver que el nuevo valor de Max_data_length: 1099511627775. De ser asi, ahora podremos almacenas mas informacion en nuestra tabla de MySQL.
Nota: Este comando en mi hardware Intel(R) Xeon(TM) CPU 2.80GHz, con 2GB de RAM se tardo 45 minutos.
Lo bueno de toda esta experiencia es que ya estamos mas preparados para migrar nuestro centro de computo para soportar alta disponibilidad de MySQL.