Prerequisites Before Upgrading to MySQL® 8

Starting with MySQL® 8, Scalingo enables group replication on all MySQL® databases. This MySQL® feature has a couple of strong prerequisites. Please make sure your database is compatible before proceeding with the upgrade:

Checking the Storage Engine

All tables must use the InnoDB storage engine. You can check which tables use a different storage engine with the following SQL statement:

SELECT table_schema, table_name FROM information_schema.tables \
  WHERE table_schema IN ('my-app-3030') AND engine != 'InnoDB';

Here is the output if the foo table uses a storage engine other than InnoDB:

+--------------+------------+
| table_schema | table_name |
+--------------+------------+
| my-app-3030  | foo        |
+--------------+------------+
1 row in set (0.00 sec)

In such a case, you need to update foo’s storage engine with the following SQL statement:

ALTER TABLE 'foo' ENGINE = 'InnoDB';

Checking Mandatory Primary Keys

All tables must have a primary key configured. You can check which tables do not have any primary key with the following SQL statement:

SELECT information_schema.tables.table_schema, information_schema.tables.table_name \
  FROM information_schema.tables LEFT JOIN information_schema.key_column_usage AS c ON (\
    information_schema.tables.table_name = c.table_name AND \
    c.constraint_schema = information_schema.tables.table_schema AND \
    c.constraint_name = 'PRIMARY' \
  ) \
  WHERE information_schema.tables.table_schema IN ('my-app-3030') AND \
  information_schema.tables.table_type != "VIEW" AND \
  c.constraint_name IS NULL;

Here is the output if the foo table does not have a primary key:

+--------------+------------+
| table_schema | table_name |
+--------------+------------+
| my-app-3030  | foo        |
+--------------+------------+
1 row in set (0.00 sec)

In such a case, you need to add a primary key to the foo table. You need to evaluate the impact of this modification before proceeding. Here is an example SQL statement to add a new column and set it as primary:

ALTER TABLE 'foo' ADD COLUMN <column description> PRIMARY KEY;

One Command Script

Below is a script that can be run directly on the database to:

  • create missing primary keys for the concerned tables
  • set the engine to InnoDB for the concerned tables

The script creates two procedures, one for each previous actions.

DELIMITER $$
DROP PROCEDURE IF EXISTS `create_missing_pk`$$

CREATE PROCEDURE `create_missing_pk`()
BEGIN

DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_table VARCHAR(100) DEFAULT "";
DECLARE stmt VARCHAR(500) DEFAULT "";

-- get the list of tables without PK
DECLARE table_cursor CURSOR FOR
SELECT i.table_name \
  FROM information_schema.tables AS i LEFT JOIN information_schema.key_column_usage AS c ON (\
    i.table_name = c.table_name AND \
    c.constraint_schema = i.table_schema AND \
    c.constraint_name = 'PRIMARY' \
  ) \
  WHERE i.table_schema \
    NOT IN ('information_schema', 'performance_schema', 'sys', 'mysql', 'mysql_innodb_cluster_metadata') AND \
    i.table_type != "VIEW" AND \
    c.constraint_name IS NULL;

DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;

OPEN table_cursor;

-- loop over all tables without PK
alter_tables: LOOP

    FETCH table_cursor INTO v_table;
    IF v_finished = 1 THEN
    LEAVE alter_tables;
    END IF;

    -- below the alter table which create PKs
    SET @prepstmt = CONCAT('ALTER TABLE ',v_table,' ADD COLUMN generated_pk INT AUTO_INCREMENT NOT NULL PRIMARY KEY FIRST;');

    PREPARE stmt FROM @prepstmt;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

END LOOP alter_tables;

CLOSE table_cursor;

END$$

-- Procedure to set engine to InnoDB
DROP PROCEDURE IF EXISTS `set_innodb_engine`$$

CREATE PROCEDURE `set_innodb_engine`()
BEGIN

DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_table VARCHAR(100) DEFAULT "";
DECLARE stmt VARCHAR(500) DEFAULT "";

-- get the list of tables without InnoDB engine
DECLARE table_cursor CURSOR FOR
SELECT table_name \
  FROM information_schema.tables \
  WHERE table_schema \
    NOT IN ('information_schema', 'performance_schema', 'sys', 'mysql', 'mysql_innodb_cluster_metadata') AND \
    table_type != "VIEW" AND \
    ENGINE != 'InnoDB';

DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;

OPEN table_cursor;

-- loop over all tables without InnoDB engine
alter_tables: LOOP

    FETCH table_cursor INTO v_table;
    IF v_finished = 1 THEN
    LEAVE alter_tables;
    END IF;

    -- below the alter table which set the engine to InnoDB
    SET @prepstmt = CONCAT('ALTER TABLE ',v_table,' ENGINE = "InnoDB";');

    PREPARE stmt FROM @prepstmt;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

END LOOP alter_tables;

CLOSE table_cursor;

END$$
DELIMITER ;

-- then call the procedures
call create_missing_pk;
call set_innodb_engine;

-- clear procedures
DROP PROCEDURE IF EXISTS `create_missing_pk`;
DROP PROCEDURE IF EXISTS `set_innodb_engine`;

-- check the current configuration of table
SELECT i.table_schema, i.table_name, i.engine, c.constraint_name  \
  FROM information_schema.tables AS i LEFT JOIN information_schema.key_column_usage AS c ON (\
    i.table_name = c.table_name AND \
    c.constraint_schema = i.table_schema AND \
    c.constraint_name = 'PRIMARY' \
  ) \
  WHERE i.table_schema not in ('information_schema', 'performance_schema', 'sys', 'mysql', 'mysql_innodb_cluster_metadata');

Suggest edits

Prerequisites Before Upgrading to MySQL® 8

©2024 Scalingo