|
The threshold at which INSTANT adding a VARCHAR is no longer possible is at 2027/2028 characters when using utf8mb4 and 2703/2704 characters with utf8mb3; or at around 8110 bytes in both cases.
So it looks to be related to the max. row length, when the max column size exceeds that then INSTANT is no longer possible?
I could not find this limitation being documented anywhere ...
|
|
I do not think that your methodology for detecting a table rebuild is correct. The file timestamp could also change due to page flushing during any DML workload. You should check if the file inode changed. That you might do by creating a hard link to the file (ln nil_test.ibd hardlink) before the ALTER TABLE and then checking if the link count of both files remains 2. If not, the original nil_test.ibd file was deleted and a new one created.
I tested the following:
--source include/have_innodb.inc
|
|
CREATE TABLE t1(id INT, name VARCHAR(10)) ENGINE=InnoDB;
|
INSERT INTO t1 VALUES(1,'abc'),(2,'def');
|
SELECT space INTO @s FROM information_schema.innodb_sys_tables
|
WHERE name='test/t1';
|
ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20)), ALGORITHM=NOCOPY;
|
SELECT space=@s FROM information_schema.innodb_sys_tables WHERE name='test/t1';
|
DROP TABLE t1;
|
The second SELECT statement is returning 1, showing that the tablespace ID did not change. If I replace ALGORITHM=NOCOPY with FORCE, then the SELECT will return 0. The tablespace ID would change on any rebuild, unless you are using innodb_file_per_table=0 and the table is located in the system tablespace (not in an .ibd file).
I tested this both on a 11.x development branch as of today, and on a build of the mariadb-10.5.21 release tag. For the latter, this is the result:
|
mariadb-10.5.21
|
CREATE TABLE t1(id INT, name VARCHAR(10)) ENGINE=InnoDB;
|
INSERT INTO t1 VALUES(1,'abc'),(2,'def');
|
SELECT space INTO @s FROM information_schema.innodb_sys_tables
|
WHERE name='test/t1';
|
ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20)), ALGORITHM=NOCOPY;
|
SELECT space=@s FROM information_schema.innodb_sys_tables WHERE name='test/t1';
|
space=@s
|
1
|
DROP TABLE t1;
|
I think that we need more information from the original environment where this happened. The contents of information_schema.innodb_sys_tables and information_schema.innodb_sys_tablespaces for this table would be a start. Is instant ADD COLUMN prevented by innodb_instant_alter_column_allowed=never (MDEV-20590)?
|
|
Hi marko, I think you were not able to reproduce it because you were using latin1 and not utf8. I've tested with both and found out that if you create table with utf8 (DEFAULT CHARSET = utf8 COLLATE = utf8_general_ci ) then table is getting rebuild.
CREATE TABLE t1(id INT, name VARCHAR(10)) ENGINE=InnoDB;
|
INSERT INTO t1 VALUES(1,'abc'),(2,'def');
|
SELECT * FROM information_schema.innodb_sys_tables
|
WHERE name='test/t1';
|
ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20)), ALGORITHM=NOCOPY;
|
SELECT * FROM information_schema.innodb_sys_tables WHERE name='test/t1';
|
SELECT table_schema, table_name, table_type, engine, row_format, table_collation FROM information_schema.tables WHERE table_schema= 'test' and table_name='t1';
|
DROP TABLE t1;
|
CREATE TABLE t1(id INT, name VARCHAR(10)) DEFAULT CHARSET = utf8 COLLATE = utf8_general_ci ENGINE=InnoDB;
|
INSERT INTO t1 VALUES(1,'abc'),(2,'def');
|
SELECT * FROM information_schema.innodb_sys_tables
|
WHERE name='test/t1';
|
ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20));
|
SELECT * FROM information_schema.innodb_sys_tables WHERE name='test/t1';
|
SELECT table_schema, table_name, table_type, engine, row_format, table_collation FROM information_schema.tables WHERE table_schema= 'test' and table_name='t1';
|
DROP TABLE t1;
|
MariaDB [test]> CREATE TABLE t1(id INT, name VARCHAR(10)) DEFAULT CHARSET = utf8 COLLATE = utf8_general_ci ENGINE=InnoDB;
|
Query OK, 0 rows affected (0.056 sec)
|
|
MariaDB [test]> INSERT INTO t1 VALUES(1,'abc'),(2,'def');
|
Query OK, 2 rows affected (0.040 sec)
|
Records: 2 Duplicates: 0 Warnings: 0
|
|
MariaDB [test]> SELECT * FROM information_schema.innodb_sys_tables
|
-> WHERE name='test/t1';
|
+----------+---------+------+--------+-------+------------+---------------+------------+
|
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
|
+----------+---------+------+--------+-------+------------+---------------+------------+
|
| 67 | test/t1 | 33 | 5 | 53 | Dynamic | 0 | Single |
|
+----------+---------+------+--------+-------+------------+---------------+------------+
|
1 row in set (0.003 sec)
|
|
MariaDB [test]> ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20));
|
Query OK, 0 rows affected (0.149 sec)
|
Records: 0 Duplicates: 0 Warnings: 0
|
|
MariaDB [test]> SELECT * FROM information_schema.innodb_sys_tables WHERE name='test/t1';
|
+----------+---------+------+--------+-------+------------+---------------+------------+
|
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
|
+----------+---------+------+--------+-------+------------+---------------+------------+
|
| 68 | test/t1 | 33 | 7 | 54 | Dynamic | 0 | Single |
|
+----------+---------+------+--------+-------+------------+---------------+------------+
|
1 row in set (0.001 sec)
|
|
MariaDB [test]> SELECT table_schema, table_name, table_type, engine, row_format, table_collation FROM information_schema.tables WHERE table_schema= 'test' and table_name='t1';
|
+--------------+------------+------------+--------+------------+-----------------+
|
| table_schema | table_name | table_type | engine | row_format | table_collation |
|
+--------------+------------+------------+--------+------------+-----------------+
|
| test | t1 | BASE TABLE | InnoDB | Dynamic | utf8_general_ci |
|
+--------------+------------+------------+--------+------------+-----------------+
|
1 row in set (0.002 sec)
|
|
MariaDB [test]> DROP TABLE t1;
|
Query OK, 0 rows affected (0.009 sec)
|
|
|
|
niljoshi, thank you. The following will not rebuild the table:
--source include/have_innodb.inc
|
|
CREATE TABLE t1(id INT, name VARCHAR(10)) ENGINE=InnoDB
|
DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
|
INSERT INTO t1 VALUES(1,'abc'),(2,'def');
|
SELECT space INTO @s FROM information_schema.innodb_sys_tables
|
WHERE name='test/t1';
|
SET STATEMENT innodb_strict_mode=OFF FOR
|
ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20)), ALGORITHM=NOCOPY;
|
SELECT space=@s FROM information_schema.innodb_sys_tables WHERE name='test/t1';
|
DROP TABLE t1;
|
If I comment out the line SET STATEMENT innodb_strict_mode=OFF FOR, then it will fail as follows:
|
10.6 d06b6de3050180ec2f96ef00963d1beab8e1b47a
|
mysqltest: At line 9: query 'ALTER TABLE t1 ADD (address VARCHAR(5000), city VARCHAR(20)), ALGORITHM=NOCOPY' failed: ER_ALTER_OPERATION_NOT_SUPPORTED (1845): ALGORITHM=NOCOPY is not supported for this operation. Try ALGORITHM=INPLACE
|
The reason for the failure is that the maximum length of the column (5000 characters*3 bytes/character = 15000 characters) is more than the record payload size (somewhere around 8000 bytes for the default innodb_page_size=16k). If I execute this with innodb_page_size=32k, then it will work. The maximum record size (for any innodb_page_size) is 16383 bytes.
I think that this is a bug in instant_alter_column_possible(), because as far as the .ibd file is concerned, the operation should be equivalent to the following, which will pass:
ALTER TABLE t1 ADD (address TEXT, city VARCHAR(20)), ALGORITHM=NOCOPY;
|
|