Browse Source
Implement worklog #5743 InnoDB: Lift the limit of index key prefixes.
Implement worklog #5743 InnoDB: Lift the limit of index key prefixes.
With this change, the index prefix column length lifted from 767 bytes to 3072 bytes if "innodb_large_prefix" is set to "true". rb://603 approved by Markopull/374/head
31 changed files with 827 additions and 156 deletions
-
3include/my_base.h
-
92mysql-test/suite/innodb/r/innodb-index.result
-
185mysql-test/suite/innodb/r/innodb_index_large_prefix.result
-
50mysql-test/suite/innodb/t/innodb-index.test
-
271mysql-test/suite/innodb/t/innodb_index_large_prefix.test
-
2mysql-test/suite/sys_vars/r/all_vars.result
-
3mysys/my_handler_errors.h
-
4sql/handler.cc
-
3sql/share/errmsg-utf8.txt
-
8storage/innobase/data/data0data.c
-
60storage/innobase/dict/dict0dict.c
-
4storage/innobase/dict/dict0load.c
-
1storage/innobase/dict/dict0mem.c
-
24storage/innobase/handler/ha_innodb.cc
-
34storage/innobase/handler/handler0alter.cc
-
2storage/innobase/include/db0err.h
-
13storage/innobase/include/dict0dict.h
-
26storage/innobase/include/dict0dict.ic
-
42storage/innobase/include/dict0mem.h
-
20storage/innobase/include/rem0types.h
-
13storage/innobase/include/row0ext.h
-
9storage/innobase/include/row0ext.ic
-
2storage/innobase/page/page0zip.c
-
2storage/innobase/rem/rem0rec.c
-
19storage/innobase/row/row0ext.c
-
11storage/innobase/row/row0mysql.c
-
5storage/innobase/row/row0row.c
-
11storage/innobase/row/row0sel.c
-
4storage/innobase/row/row0upd.c
-
58storage/innobase/trx/trx0rec.c
-
2storage/innobase/ut/ut0ut.c
@ -0,0 +1,185 @@ |
|||
set global innodb_file_format="Barracuda"; |
|||
set global innodb_file_per_table=1; |
|||
set global innodb_large_prefix=1; |
|||
create table worklog5743(a TEXT not null, primary key (a(1000))) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
insert into worklog5743 values(repeat("a", 20000)); |
|||
update worklog5743 set a = (repeat("b", 16000)); |
|||
create index idx on worklog5743(a(2000)); |
|||
begin; |
|||
update worklog5743 set a = (repeat("x", 17000)); |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
REPEATABLE-READ |
|||
select a = repeat("x", 17000) from worklog5743; |
|||
a = repeat("x", 17000) |
|||
0 |
|||
select a = repeat("b", 16000) from worklog5743; |
|||
a = repeat("b", 16000) |
|||
1 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
READ-UNCOMMITTED |
|||
select a = repeat("x", 17000) from worklog5743; |
|||
a = repeat("x", 17000) |
|||
1 |
|||
rollback; |
|||
drop table worklog5743; |
|||
create table worklog5743(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
create index idx on worklog5743(a1, a2(2000)); |
|||
insert into worklog5743 values(9, repeat("a", 10000)); |
|||
begin; |
|||
update worklog5743 set a1 = 1000; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
REPEATABLE-READ |
|||
explain select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
id select_type table type possible_keys key key_len ref rows Extra |
|||
1 SIMPLE worklog5743 ref idx idx 5 const 1 Using where |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
9 1 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
READ-UNCOMMITTED |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
rollback; |
|||
drop table worklog5743; |
|||
create table worklog5743(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
create index idx on worklog5743(a1, a2(50)); |
|||
insert into worklog5743 values(9, repeat("a", 10000)); |
|||
begin; |
|||
update worklog5743 set a1 = 1000; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
REPEATABLE-READ |
|||
explain select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
id select_type table type possible_keys key key_len ref rows Extra |
|||
1 SIMPLE worklog5743 ref idx idx 5 const 1 Using where |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
9 1 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
READ-UNCOMMITTED |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
rollback; |
|||
drop table worklog5743; |
|||
create table worklog5743_2(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2, engine = innodb; |
|||
create table worklog5743_4(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4, engine = innodb; |
|||
create index idx1 on worklog5743_2(a1, a2(942)); |
|||
ERROR HY000: Too big row |
|||
create index idx1 on worklog5743_2(a1, a2(940)); |
|||
create index idx1 on worklog5743_4(a1, a2(1966)); |
|||
ERROR HY000: Too big row |
|||
create index idx1 on worklog5743_4(a1, a2(1964)); |
|||
insert into worklog5743_2 values(9, repeat("a", 10000)); |
|||
insert into worklog5743_4 values(9, repeat("a", 10000)); |
|||
begin; |
|||
update worklog5743_2 set a1 = 1000; |
|||
update worklog5743_4 set a1 = 1000; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
REPEATABLE-READ |
|||
explain select a1, a2 = repeat("a", 10000) from worklog5743_2 where a1 = 9; |
|||
id select_type table type possible_keys key key_len ref rows Extra |
|||
1 SIMPLE worklog5743_2 ref idx1 idx1 5 const 1 Using where |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_2 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
9 1 |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_4 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
9 1 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
READ-UNCOMMITTED |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_2 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_4 where a1 = 9; |
|||
a1 a2 = repeat("a", 10000) |
|||
rollback; |
|||
drop table worklog5743_2; |
|||
drop table worklog5743_4; |
|||
create table worklog5743(a1 int, a2 varchar(3000)) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
create index idx on worklog5743(a1, a2); |
|||
insert into worklog5743 values(9, repeat("a", 3000)); |
|||
begin; |
|||
update worklog5743 set a1 = 1000; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
REPEATABLE-READ |
|||
explain select a1 from worklog5743 where a1 = 9; |
|||
id select_type table type possible_keys key key_len ref rows Extra |
|||
1 SIMPLE worklog5743 ref idx idx 5 const 1 Using where; Using index |
|||
select a1 from worklog5743 where a1 = 9; |
|||
a1 |
|||
9 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
READ-UNCOMMITTED |
|||
select a1 from worklog5743 where a1 = 9; |
|||
a1 |
|||
rollback; |
|||
drop table worklog5743; |
|||
create table worklog5743(a TEXT not null, primary key (a(1000))) |
|||
engine = innodb; |
|||
ERROR HY000: Index column size too large. The maximum column size is 767 bytes. |
|||
create table worklog5743(a TEXT) engine = innodb; |
|||
create index idx on worklog5743(a(1000)); |
|||
ERROR HY000: Index column size too large. The maximum column size is 767 bytes. |
|||
create index idx on worklog5743(a(725)); |
|||
insert into worklog5743 values(repeat("a", 20000)); |
|||
begin; |
|||
insert into worklog5743 values(repeat("b", 20000)); |
|||
update worklog5743 set a = (repeat("x", 25000)); |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
REPEATABLE-READ |
|||
select a = repeat("a", 20000) from worklog5743; |
|||
a = repeat("a", 20000) |
|||
1 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
@@session.tx_isolation |
|||
READ-UNCOMMITTED |
|||
select a = repeat("x", 25000) from worklog5743; |
|||
a = repeat("x", 25000) |
|||
1 |
|||
1 |
|||
rollback; |
|||
drop table worklog5743; |
|||
create table worklog5743(a TEXT not null) ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
create index idx on worklog5743(a(3073)); |
|||
Warnings: |
|||
Warning 1071 Specified key was too long; max key length is 3072 bytes |
|||
Warning 1071 Specified key was too long; max key length is 3072 bytes |
|||
create index idx2 on worklog5743(a(3072)); |
|||
show create table worklog5743; |
|||
Table Create Table |
|||
worklog5743 CREATE TABLE `worklog5743` ( |
|||
`a` text NOT NULL, |
|||
KEY `idx` (`a`(3072)), |
|||
KEY `idx2` (`a`(3072)) |
|||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC |
|||
drop table worklog5743; |
|||
create table worklog5743(a TEXT not null) engine = innodb; |
|||
create index idx on worklog5743(a(768)); |
|||
ERROR HY000: Index column size too large. The maximum column size is 767 bytes. |
|||
create index idx2 on worklog5743(a(767)); |
|||
drop table worklog5743; |
|||
SET GLOBAL innodb_file_format=Antelope; |
|||
SET GLOBAL innodb_file_per_table=0; |
|||
SET GLOBAL innodb_file_format_max=Antelope; |
|||
SET GLOBAL innodb_large_prefix=0; |
|||
@ -0,0 +1,271 @@ |
|||
# Testcase for worklog #5743: Lift the limit of index key prefixes |
|||
|
|||
--source include/have_innodb.inc |
|||
|
|||
let $innodb_file_format_orig=`select @@innodb_file_format`; |
|||
let $innodb_file_per_table_orig=`select @@innodb_file_per_table`; |
|||
let $innodb_file_format_max_orig=`select @@innodb_file_format_max`; |
|||
let $innodb_large_prefix_orig=`select @@innodb_large_prefix`; |
|||
|
|||
set global innodb_file_format="Barracuda"; |
|||
set global innodb_file_per_table=1; |
|||
set global innodb_large_prefix=1; |
|||
|
|||
# Create a table of DYNAMIC format, with a primary index of 1000 bytes in |
|||
# size |
|||
create table worklog5743(a TEXT not null, primary key (a(1000))) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
|
|||
# Do some insertion and update to excercise the external cache |
|||
# code path |
|||
insert into worklog5743 values(repeat("a", 20000)); |
|||
|
|||
# default session, update the table |
|||
update worklog5743 set a = (repeat("b", 16000)); |
|||
|
|||
# Create a secondary index |
|||
create index idx on worklog5743(a(2000)); |
|||
|
|||
# Start a few sessions to do selections on table being updated in default |
|||
# session, so it would rebuild the previous version from undo log. |
|||
# 1) Default session: Initiate an update on the externally stored column |
|||
# 2) Session con1: Select from table with repeated read |
|||
# 3) Session con2: Select from table with read uncommitted |
|||
# 4) Default session: rollback updates |
|||
|
|||
begin; |
|||
update worklog5743 set a = (repeat("x", 17000)); |
|||
|
|||
# Start a new session to select the column to force it build |
|||
# an earlier version of the clustered index through undo log. So it should |
|||
# just see the result of repeat("b", 16000) |
|||
select @@session.tx_isolation; |
|||
--connect (con1,localhost,root,,) |
|||
select a = repeat("x", 17000) from worklog5743; |
|||
select a = repeat("b", 16000) from worklog5743; |
|||
|
|||
# Start another session doing "read uncommitted" query, it |
|||
# should see the uncommitted update |
|||
--connect (con2,localhost,root,,) |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
select a = repeat("x", 17000) from worklog5743; |
|||
|
|||
# Roll back the transaction |
|||
--connection default |
|||
rollback; |
|||
|
|||
drop table worklog5743; |
|||
|
|||
# Create a table with only a secondary index has large prefix column |
|||
create table worklog5743(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
|
|||
create index idx on worklog5743(a1, a2(2000)); |
|||
|
|||
insert into worklog5743 values(9, repeat("a", 10000)); |
|||
|
|||
begin; |
|||
|
|||
update worklog5743 set a1 = 1000; |
|||
|
|||
# Do a select from another connection that would use the secondary index |
|||
--connection con1 |
|||
select @@session.tx_isolation; |
|||
explain select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
|
|||
# Do read uncommitted in another session, it would show there is no |
|||
# row with a1 = 9 |
|||
--connection con2 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
|
|||
--connection default |
|||
rollback; |
|||
|
|||
drop table worklog5743; |
|||
|
|||
# Create a table with a secondary index has small (50 bytes) prefix column |
|||
create table worklog5743(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
|
|||
create index idx on worklog5743(a1, a2(50)); |
|||
|
|||
insert into worklog5743 values(9, repeat("a", 10000)); |
|||
|
|||
begin; |
|||
|
|||
update worklog5743 set a1 = 1000; |
|||
|
|||
# Do a select from another connection that would use the secondary index |
|||
--connection con1 |
|||
select @@session.tx_isolation; |
|||
explain select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
|
|||
# Do read uncommitted in another session, it would show there is no |
|||
# row with a1 = 9 |
|||
--connection con2 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743 where a1 = 9; |
|||
|
|||
--connection default |
|||
rollback; |
|||
|
|||
drop table worklog5743; |
|||
|
|||
# Create a table of ROW_FORMAT=COMPRESSED format |
|||
create table worklog5743_2(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2, engine = innodb; |
|||
|
|||
create table worklog5743_4(a1 int, a2 TEXT not null) |
|||
ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4, engine = innodb; |
|||
|
|||
# The maximum overall index record (not prefix) length for this table |
|||
# is page_zip_empty_size() / 2, which is 960. "Too big row" error ( |
|||
# HA_ERR_TO_BIG_ROW) will be printed if this limit is exceeded. |
|||
# Considering other fields and their overhead, the maximum length |
|||
# for column a2 is 940 or 941 depending on the zlib version used and |
|||
# compressBound() value used in page_zip_empty_size() (please refer |
|||
# to Bug #47495 for more detail). |
|||
-- error 139 |
|||
create index idx1 on worklog5743_2(a1, a2(942)); |
|||
|
|||
create index idx1 on worklog5743_2(a1, a2(940)); |
|||
|
|||
# similarly, the maximum index record length for the table is |
|||
# 1984. Considering other fields and their overhead, the |
|||
# maximum length for column a2 is 1964 or 1965 (please refer |
|||
# to Bug #47495 for more detail). |
|||
-- error 139 |
|||
create index idx1 on worklog5743_4(a1, a2(1966)); |
|||
|
|||
create index idx1 on worklog5743_4(a1, a2(1964)); |
|||
|
|||
insert into worklog5743_2 values(9, repeat("a", 10000)); |
|||
insert into worklog5743_4 values(9, repeat("a", 10000)); |
|||
|
|||
begin; |
|||
|
|||
update worklog5743_2 set a1 = 1000; |
|||
update worklog5743_4 set a1 = 1000; |
|||
|
|||
# Do a select from another connection that would use the secondary index |
|||
--connection con1 |
|||
select @@session.tx_isolation; |
|||
explain select a1, a2 = repeat("a", 10000) from worklog5743_2 where a1 = 9; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_2 where a1 = 9; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_4 where a1 = 9; |
|||
|
|||
# Do read uncommitted in another session, it would show there is no |
|||
# row with a1 = 9 |
|||
--connection con2 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_2 where a1 = 9; |
|||
select a1, a2 = repeat("a", 10000) from worklog5743_4 where a1 = 9; |
|||
|
|||
--connection default |
|||
rollback; |
|||
|
|||
drop table worklog5743_2; |
|||
drop table worklog5743_4; |
|||
|
|||
# Create a table with varchar column, and create index directly on this |
|||
# large column (without prefix) |
|||
create table worklog5743(a1 int, a2 varchar(3000)) |
|||
ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
|
|||
# Create an index with large column without prefix |
|||
create index idx on worklog5743(a1, a2); |
|||
|
|||
insert into worklog5743 values(9, repeat("a", 3000)); |
|||
|
|||
begin; |
|||
|
|||
update worklog5743 set a1 = 1000; |
|||
|
|||
# Do a select from another connection that would use the secondary index |
|||
--connection con1 |
|||
select @@session.tx_isolation; |
|||
explain select a1 from worklog5743 where a1 = 9; |
|||
select a1 from worklog5743 where a1 = 9; |
|||
|
|||
# Do read uncommitted, it would show there is no row with a1 = 9 |
|||
--connection con2 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
select a1 from worklog5743 where a1 = 9; |
|||
|
|||
--connection default |
|||
rollback; |
|||
|
|||
drop table worklog5743; |
|||
|
|||
# Create a table with old format, and the limit is 768 bytes. |
|||
-- error ER_INDEX_COLUMN_TOO_LONG |
|||
create table worklog5743(a TEXT not null, primary key (a(1000))) |
|||
engine = innodb; |
|||
|
|||
create table worklog5743(a TEXT) engine = innodb; |
|||
|
|||
# Excercise the column length check in ha_innobase::add_index() |
|||
-- error ER_INDEX_COLUMN_TOO_LONG |
|||
create index idx on worklog5743(a(1000)); |
|||
|
|||
# This should be successful |
|||
create index idx on worklog5743(a(725)); |
|||
|
|||
# Perform some DMLs |
|||
insert into worklog5743 values(repeat("a", 20000)); |
|||
|
|||
begin; |
|||
insert into worklog5743 values(repeat("b", 20000)); |
|||
update worklog5743 set a = (repeat("x", 25000)); |
|||
|
|||
# Start a new session to select the table to force it build |
|||
# an earlier version of the cluster index through undo log |
|||
select @@session.tx_isolation; |
|||
--connection con1 |
|||
select a = repeat("a", 20000) from worklog5743; |
|||
|
|||
--connection con2 |
|||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
|||
select @@session.tx_isolation; |
|||
select a = repeat("x", 25000) from worklog5743; |
|||
|
|||
--connection default |
|||
rollback; |
|||
|
|||
drop table worklog5743; |
|||
|
|||
# Some border line test on the column length. |
|||
# We have a limit of 3072 bytes for Barracuda table |
|||
create table worklog5743(a TEXT not null) ROW_FORMAT=DYNAMIC, engine = innodb; |
|||
|
|||
# Length exceeds maximum supported key length, will auto-truncated to 3072 |
|||
create index idx on worklog5743(a(3073)); |
|||
|
|||
create index idx2 on worklog5743(a(3072)); |
|||
|
|||
show create table worklog5743; |
|||
|
|||
drop table worklog5743; |
|||
|
|||
# We have a limit of 767 bytes for Antelope table |
|||
create table worklog5743(a TEXT not null) engine = innodb; |
|||
|
|||
-- error ER_INDEX_COLUMN_TOO_LONG |
|||
create index idx on worklog5743(a(768)); |
|||
|
|||
create index idx2 on worklog5743(a(767)); |
|||
|
|||
drop table worklog5743; |
|||
|
|||
eval SET GLOBAL innodb_file_format=$innodb_file_format_orig; |
|||
eval SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig; |
|||
eval SET GLOBAL innodb_file_format_max=$innodb_file_format_max_orig; |
|||
eval SET GLOBAL innodb_large_prefix=$innodb_large_prefix_orig; |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue