[comment]: # ({e26480a0-e26480a0})
# 3 Actualización de la base de datos a claves primarias

[comment]: # ({/e26480a0-e26480a0})

[comment]: # ({c4558d36-53564572})
### Descripción general

Esta sección proporciona instrucciones para actualizar manualmente las tablas en instalaciones existentes a claves primarias.

Actualizar a claves primarias optimiza cómo se indexan y acceden los datos, lo que puede acelerar las consultas y ahorrar espacio.
También mejora la gestión y sincronización de datos en configuraciones en clúster, ayudando con la escalabilidad y asegurando que el sistema siga siendo fiable incluso si algunos servidores fallan.

::: noteimportant
Las instrucciones proporcionadas en esta página están diseñadas para usuarios avanzados y pueden necesitar ser ajustadas para su configuración específica.
Actualizar a claves primarias puede llevar mucho tiempo y requerir muchos recursos.
Asegúrese de que haya suficiente espacio libre en disco; dependiendo del tamaño de su base de datos y los datos almacenados, el proceso puede requerir hasta 2,5 veces el espacio que actualmente utilizan las tablas de histórico.
:::

Las claves primarias se utilizan para todas las tablas en instalaciones nuevas desde Zabbix 6.0.

No existe una actualización automática de la base de datos a claves primarias; sin embargo, las instalaciones existentes pueden actualizarse manualmente **después** de actualizar el servidor Zabbix a la versión 6.0 o posterior.

::: noteimportant
Desde Zabbix 7.0, actualizar las tablas a claves primarias también actualiza las tablas para usar tipos de datos de doble precisión.
<br><br>
Si tiene Zabbix 7.0 (o posterior), las tablas ya usan doble precisión.
Sin embargo, las instrucciones de esta página aún pueden seguirse para actualizar las tablas a claves primarias sin afectar a las tablas que ya usan doble precisión.
<br><br>
Si tiene Zabbix 6.4 (o anterior), considere actualizar primero las tablas a doble precisión.
Para más información, consulte [Actualización a valores numéricos de rango extendido](https://www.zabbix.com/documentation/7.0/en/manual/appendix/install/db_float_range) en la documentación de Zabbix 7.0.
:::

Las instrucciones están disponibles para:

* [MySQL](#mysql)
* [PostgreSQL](#postgresql)
* [TimescaleDB](#postgresql-timescaledb)

[comment]: # ({/c4558d36-53564572})

[comment]: # ({5c5adaf8-980f7329})
### Notas importantes

Para realizar la actualización de la base de datos:

1. Detenga el servidor Zabbix.

Se recomienda encarecidamente detener el servidor Zabbix durante el tiempo de la actualización.
Sin embargo, si es absolutamente necesario, puede realizar la actualización mientras el servidor está en funcionamiento (solo para MySQL, MariaDB y PostgreSQL sin TimescaleDB).

2. Realice una copia de seguridad de su base de datos.
3. Instale el paquete zabbix-sql-scripts más reciente compatible con su versión de Zabbix (por ejemplo, para RHEL: `dnf install zabbix-sql-scripts`).
4. Ejecute los scripts para su base de datos.
5. Inicie el servidor Zabbix.

::: notewarning
Ejecute los scripts solo para la base de datos del servidor.
El proxy no se beneficiará de esta actualización.
:::

Si la base de datos utiliza particiones, contacte al administrador de la base de datos o al Soporte de Zabbix para obtener ayuda.

Los archivos CSV pueden eliminarse después de una actualización exitosa a claves primarias.

Opcionalmente, la interfaz web de Zabbix puede cambiarse a [modo de mantenimiento](/manual/web_interface/maintenance_mode).

[comment]: # ({/5c5adaf8-980f7329})

[comment]: # ({4f99bcf1-1551eb55})
### MySQL

La exportación e importación deben realizarse en tmux/screen para asegurarse de que la sesión no se interrumpa.

Consulte también: [Notas importantes](#important-notes)

[comment]: # ({/4f99bcf1-1551eb55})

[comment]: # ({5bf5d8c3-dc89d749})
#### MySQL 8.4+ con mysqlsh

Este método se puede utilizar con un servidor Zabbix en funcionamiento, pero se recomienda detener el servidor durante la actualización.
El Shell de MySQL (*mysqlsh*) debe estar [instalado](https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-install-linux-quick.html) y poder conectarse a la base de datos.

* Inicie sesión en la consola de MySQL como root (recomendado) o como cualquier usuario con privilegios FILE.

* Inicie MySQL con la variable [local_infile](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_local_infile) habilitada.

* Cambie el nombre de las tablas antiguas y cree nuevas tablas ejecutando `history_upgrade_prepare.sql`.

```bash
mysql -uzabbix -p<contraseña> zabbix < /usr/share/zabbix/sql-scripts/mysql/option-patches/history_upgrade_prepare.sql
```

* Exporte e importe los datos.

Conéctese a través de mysqlsh. Si utiliza una conexión por socket, puede ser necesario especificar la ruta.

```bash
sudo mysqlsh -uroot -S /run/mysqld/mysqld.sock --no-password -Dzabbix
```

Cambie al modo JavaScript usando:

```sqlmysql
\js
```

Luego ejecute el siguiente código (CSVPATH se puede cambiar según sea necesario):

```javascript
CSVPATH="/var/lib/mysql-files";

util.exportTable("history_old", CSVPATH + "/history.csv", { dialect: "csv" });
util.importTable(CSVPATH + "/history.csv", {"dialect": "csv", "table": "history" });

util.exportTable("history_uint_old", CSVPATH + "/history_uint.csv", { dialect: "csv" });
util.importTable(CSVPATH + "/history_uint.csv", {"dialect": "csv", "table": "history_uint" });

util.exportTable("history_str_old", CSVPATH + "/history_str.csv", { dialect: "csv" });
util.importTable(CSVPATH + "/history_str.csv", {"dialect": "csv", "table": "history_str" });

util.exportTable("history_log_old", CSVPATH + "/history_log.csv", { dialect: "csv" });
util.importTable(CSVPATH + "/history_log.csv", {"dialect": "csv", "table": "history_log" });

util.exportTable("history_text_old", CSVPATH + "/history_text.csv", { dialect: "csv" });
util.importTable(CSVPATH + "/history_text.csv", {"dialect": "csv", "table": "history_text" });
```

Si recibe el mensaje "JavaScript is not supported", su instalación de MySQL Shell no tiene soporte para JS.
En ese caso, instale el [paquete oficial de MySQL Shell](https://dev.mysql.com/downloads/shell/) de Oracle (o compílelo desde el código fuente) para que el modo JavaScript esté habilitado.

* Siga las [instrucciones posteriores a la migración](#post-migration) para eliminar las tablas antiguas.

[comment]: # ({/5bf5d8c3-dc89d749})

[comment]: # ({e9cf2797-b132f69b})
#### MariaDB/MySQL 8.4+ sin mysqlsh

Este método de actualización toma más tiempo y debe usarse solo si no es posible una actualización con *mysqlsh*.

##### Actualización de tablas

* Inicie sesión en la consola de MySQL como root (recomendado) o cualquier usuario con privilegios FILE.

* Si realiza la migración con un servidor Zabbix en ejecución, inicie MySQL con la variable [local_infile](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_local_infile) habilitada.

* Renombre las tablas antiguas y cree nuevas tablas ejecutando `history_upgrade_prepare.sql`:

```bash
mysql -uzabbix -p<contraseña> zabbix < /usr/share/zabbix/sql-scripts/mysql/option-patches/history_upgrade_prepare.sql
```

##### Migración con el servidor detenido

`max_execution_time` (en MySQL) o `max_statement_time` (en MariaDB) deben estar deshabilitados antes de migrar los datos para evitar el tiempo de espera durante la migración.

Para MySQL:

```sql
SET @@max_execution_time=0;
```

Para MariaDB:

```sql
SET @@max_statement_time=0;
```

```sql
INSERT IGNORE INTO history SELECT * FROM history_old;
INSERT IGNORE INTO history_uint SELECT * FROM history_uint_old;
INSERT IGNORE INTO history_str SELECT * FROM history_str_old;
INSERT IGNORE INTO history_log SELECT * FROM history_log_old;
INSERT IGNORE INTO history_text SELECT * FROM history_text_old;
```

Siga las [instrucciones posteriores a la migración](#post-migration) para eliminar las tablas antiguas.

##### Migración con el servidor en ejecución

Verifique para qué rutas está habilitada la importación/exportación:

```sql
mysql> SELECT @@secure_file_priv;
+-----------------------+
| @@secure_file_priv    |
+-----------------------+
| /var/lib/mysql-files/ |
+-----------------------+
```

Si el valor de *secure_file_priv* es una ruta a un directorio, la exportación/importación se realizará para 
archivos en ese directorio.
En este caso, edite las rutas a los archivos en las consultas en consecuencia o establezca el valor de *secure_file_priv* en una cadena vacía durante la actualización.

Si el valor de *secure_file_priv* está vacío, la exportación/importación se puede realizar desde cualquier ubicación.

Si el valor de *secure_file_priv* es NULL, establézcalo en la ruta que contiene los datos de la tabla exportada ('/var/lib/mysql-files/' en el ejemplo anterior).

Para más información, consulte la [documentación de MySQL](https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html#sysvar_secure_file_priv) o la [documentación de MariaDB](https://mariadb.com/docs/server/ha-and-performance/optimization-and-tuning/system-variables/server-system-variables#secure_file_priv).

`max_execution_time` (en MySQL) o `max_statement_time` (en MariaDB) deben estar deshabilitados antes de exportar los datos para evitar el tiempo de espera durante la exportación.

Para MySQL:

```sql
SET @@max_execution_time=0;
```

Para MariaDB:

```sql
SET @@max_statement_time=0;
```

```sql
SELECT * INTO OUTFILE '/var/lib/mysql-files/history.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_old;
LOAD DATA INFILE '/var/lib/mysql-files/history.csv' IGNORE INTO TABLE history FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';

SELECT * INTO OUTFILE '/var/lib/mysql-files/history_uint.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_uint_old;
LOAD DATA INFILE '/var/lib/mysql-files/history_uint.csv' IGNORE INTO TABLE history_uint FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';

SELECT * INTO OUTFILE '/var/lib/mysql-files/history_str.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_str_old;
LOAD DATA INFILE '/var/lib/mysql-files/history_str.csv' IGNORE INTO TABLE history_str FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';

SELECT * INTO OUTFILE '/var/lib/mysql-files/history_log.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_log_old;
LOAD DATA INFILE '/var/lib/mysql-files/history_log.csv' IGNORE INTO TABLE history_log FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';

SELECT * INTO OUTFILE '/var/lib/mysql-files/history_text.csv' FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n' FROM history_text_old;
LOAD DATA INFILE '/var/lib/mysql-files/history_text.csv' IGNORE INTO TABLE history_text FIELDS TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '\n';
```

Siga las [instrucciones posteriores a la migración](#post-migration) para eliminar las tablas antiguas.

[comment]: # ({/e9cf2797-b132f69b})

[comment]: # ({c484c7a0-1139207b})
### PostgreSQL

La exportación e importación deben realizarse en tmux/screen para asegurar que la sesión no se interrumpa.
Para instalaciones con TimescaleDB, omita esta sección y continúe con [PostgreSQL + TimescaleDB](#postgresql-timescaledb).

Véase también: [Notas importantes](#important-notes)

#### Actualización de tablas

* Renombre las tablas usando `history_upgrade_prepare.sql`:

```bash
sudo -u zabbix psql zabbix < /usr/share/zabbix/sql-scripts/postgresql/option-patches/history_upgrade_prepare.sql
```

#### Migración con el servidor detenido

* Exporte el historial actual, impórtelo en la tabla temporal,
luego inserte los datos en las nuevas tablas ignorando los duplicados:

```sql
INSERT INTO history SELECT * FROM history_old ON CONFLICT (itemid,clock,ns) DO NOTHING;

INSERT INTO history_uint SELECT * FROM history_uint_old ON CONFLICT (itemid,clock,ns) DO NOTHING;

INSERT INTO history_str SELECT * FROM history_str_old ON CONFLICT (itemid,clock,ns) DO NOTHING;

INSERT INTO history_log SELECT * FROM history_log_old ON CONFLICT (itemid,clock,ns) DO NOTHING;

INSERT INTO history_text SELECT * FROM history_text_old ON CONFLICT (itemid,clock,ns) DO NOTHING;
```

Consulte consejos para mejorar el rendimiento de INSERT: [PostgreSQL: Bulk Loading Huge Amounts of Data](https://www.cybertec-postgresql.com/en/postgresql-bulk-loading-huge-amounts-of-data), [Checkpoint Distance and Amount of WAL](https://www.cybertec-postgresql.com/en/checkpoint-distance-and-amount-of-wal).

* Siga las [instrucciones posteriores a la migración](#post-migration) para eliminar las tablas antiguas.

[comment]: # ({/c484c7a0-1139207b})

[comment]: # ({8f70859a-7e590ff3})
#### Migración con el servidor en ejecución

* Exporte el historial actual, impórtelo en la tabla temporal,
luego inserte los datos en las nuevas tablas ignorando los duplicados:

```sql
\copy history_old TO '/tmp/history.csv' DELIMITER ',' CSV
CREATE TEMP TABLE temp_history (
    itemid                   bigint                                    NOT NULL,
    clock                    integer         DEFAULT '0'               NOT NULL,
    value                    DOUBLE PRECISION DEFAULT '0.0000'          NOT NULL,
    ns                       integer         DEFAULT '0'               NOT NULL
);
\copy temp_history FROM '/tmp/history.csv' DELIMITER ',' CSV
INSERT INTO history SELECT * FROM temp_history ON CONFLICT (itemid,clock,ns) DO NOTHING;

\copy history_uint_old TO '/tmp/history_uint.csv' DELIMITER ',' CSV
CREATE TEMP TABLE temp_history_uint (
    itemid                   bigint                                    NOT NULL,
    clock                    integer         DEFAULT '0'               NOT NULL,
    value                    numeric(20)     DEFAULT '0'               NOT NULL,
    ns                       integer         DEFAULT '0'               NOT NULL
);
\copy temp_history_uint FROM '/tmp/history_uint.csv' DELIMITER ',' CSV
INSERT INTO history_uint SELECT * FROM temp_history_uint ON CONFLICT (itemid,clock,ns) DO NOTHING;

\copy history_str_old TO '/tmp/history_str.csv' DELIMITER ',' CSV
CREATE TEMP TABLE temp_history_str (
    itemid                   bigint                                    NOT NULL,
    clock                    integer         DEFAULT '0'               NOT NULL,
    value                    varchar(255)    DEFAULT ''                NOT NULL,
    ns                       integer         DEFAULT '0'               NOT NULL
);
\copy temp_history_str FROM '/tmp/history_str.csv' DELIMITER ',' CSV
INSERT INTO history_str (itemid,clock,value,ns) SELECT * FROM temp_history_str ON CONFLICT (itemid,clock,ns) DO NOTHING;

\copy history_log_old TO '/tmp/history_log.csv' DELIMITER ',' CSV
CREATE TEMP TABLE temp_history_log (
    itemid                   bigint                                    NOT NULL,
    clock                    integer         DEFAULT '0'               NOT NULL,
    timestamp                integer         DEFAULT '0'               NOT NULL,
    source                   varchar(64)     DEFAULT ''                NOT NULL,
    severity                 integer         DEFAULT '0'               NOT NULL,
    value                    text            DEFAULT ''                NOT NULL,
    logeventid               integer         DEFAULT '0'               NOT NULL,
    ns                       integer         DEFAULT '0'               NOT NULL
);
\copy temp_history_log FROM '/tmp/history_log.csv' DELIMITER ',' CSV
INSERT INTO history_log SELECT * FROM temp_history_log ON CONFLICT (itemid,clock,ns) DO NOTHING;

\copy history_text_old TO '/tmp/history_text.csv' DELIMITER ',' CSV
CREATE TEMP TABLE temp_history_text (
    itemid                   bigint                                    NOT NULL,
    clock                    integer         DEFAULT '0'               NOT NULL,
    value                    text            DEFAULT ''                NOT NULL,
    ns                       integer         DEFAULT '0'               NOT NULL
);
\copy temp_history_text FROM '/tmp/history_text.csv' DELIMITER ',' CSV
INSERT INTO history_text SELECT * FROM temp_history_text ON CONFLICT (itemid,clock,ns) DO NOTHING;
```
* Siga las [instrucciones posteriores a la migración](#post-migration) para eliminar las tablas antiguas.

[comment]: # ({/8f70859a-7e590ff3})

[comment]: # ({b79c2974-589d2f09})
### PostgreSQL + TimescaleDB

La exportación e importación deben realizarse en tmux/screen para garantizar que la sesión no se interrumpa.
El servidor Zabbix debe estar detenido durante la actualización.

Consulte también: [Notas importantes](#important-notes)

* Cambie el nombre de las tablas usando `history_upgrade_prepare.sql`.
  * Si la compresión está habilitada (en la instalación por defecto), ejecute el script desde `/usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression`:
    ```bash
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/history_upgrade_prepare.sql | sudo -u zabbix psql zabbix
    ```
  * Si la compresión está deshabilitada, ejecute el script desde `/usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression`:
    ```bash
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/history_upgrade_prepare.sql | sudo -u zabbix psql zabbix
    ```

* Ejecute los scripts de migración de hypertables de TimescaleDB según la configuración de compresión:
  * Si la compresión está habilitada (en la instalación por defecto), ejecute los scripts desde `/usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression`:
    ```bash
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/history_upgrade.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/history_upgrade_uint.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/history_upgrade_log.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/history_upgrade_str.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/history_upgrade_text.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/with-compression/trends_upgrade.sql | sudo -u zabbix psql zabbix
    ```
  * Si la compresión está deshabilitada, ejecute los scripts desde `/usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression`:
    ```bash
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/history_upgrade.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/history_upgrade_uint.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/history_upgrade_log.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/history_upgrade_str.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/history_upgrade_text.sql | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix/sql-scripts/postgresql/timescaledb/option-patches/without-compression/trends_upgrade.sql | sudo -u zabbix psql zabbix
    ```

Consulte también: [Consejos](https://www.tigerdata.com/blog/13-tips-to-improve-postgresql-insert-performance) para mejorar el rendimiento de las operaciones INSERT.

* Siga las [instrucciones posteriores a la migración](#post-migration) para eliminar las tablas antiguas.

[comment]: # ({/b79c2974-589d2f09})

[comment]: # ({e73536ae-b041e427})
### Post-migración

Para todas las bases de datos, una vez completada la migración, haga lo siguiente:

* Verifique que todo funcione como se espera.

* Elimine las tablas antiguas:

```sql
DROP TABLE history_old;
DROP TABLE history_uint_old;
DROP TABLE history_str_old;
DROP TABLE history_log_old;
DROP TABLE history_text_old;
```

* Para TimescaleDB, elimine también la siguiente tabla antigua:

```sql
DROP TABLE trends_old;
```

[comment]: # ({/e73536ae-b041e427})

[comment]: # ({16ed11f0-8ee7d9aa})
#### Véase también

-   [Preparando la tabla auditlog para particionamiento](/manual/appendix/install/auditlog_primary_keys)

[comment]: # ({/16ed11f0-8ee7d9aa})
