mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-11 21:51:21 +00:00
PT-1572 WIP
This commit is contained in:
@@ -13262,6 +13262,10 @@ the values are converted to strings by the CONCAT() function, and MySQL chooses
|
|||||||
the string representation. If you specify a value of 2, for example, then the
|
the string representation. If you specify a value of 2, for example, then the
|
||||||
values 1.008 and 1.009 will be rounded to 1.01, and will checksum as equal.
|
values 1.008 and 1.009 will be rounded to 1.01, and will checksum as equal.
|
||||||
|
|
||||||
|
=item --force-concat-enums
|
||||||
|
|
||||||
|
bla bla bla bla bla
|
||||||
|
|
||||||
=item --function
|
=item --function
|
||||||
|
|
||||||
type: string
|
type: string
|
||||||
|
@@ -134,14 +134,37 @@ sub new {
|
|||||||
);
|
);
|
||||||
PTDEBUG && _d('Ascend params:', Dumper($asc));
|
PTDEBUG && _d('Ascend params:', Dumper($asc));
|
||||||
|
|
||||||
|
# Check if enum fields items are sorted or not.
|
||||||
|
# If they are sorted we can skip adding CONCAT to improve the queries eficiency.
|
||||||
|
my $force_concat_enums = $o->has('force-concat-enums') && $o->get('force-concat-enums');
|
||||||
|
for my $index (@{$index_cols}) {
|
||||||
|
if ($tbl->{tbl_struct}->{type_for}->{$index} eq 'enum') {
|
||||||
|
if ($tbl->{tbl_struct}->{defs}->{$index} =~ m/enum\s*\((.*?)\)/) {
|
||||||
|
my @items = split(/,\s*/, $1);
|
||||||
|
my $sorted = 1; # Asume the items list is sorted to later check if this is true
|
||||||
|
for (my $i=1; $i < scalar(@items); $i++) {
|
||||||
|
if ($items[$i-1] gt $items[$i]) {
|
||||||
|
$sorted = 0;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$force_concat_enums && !$sorted) {
|
||||||
|
die "The index " . $index . " in table " . $tbl->{name} .
|
||||||
|
" has unsorted enum items.\nPlease read the documentation for the --force-concat-enums parameter\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Make SQL statements, prepared on first call to next(). FROM and
|
# Make SQL statements, prepared on first call to next(). FROM and
|
||||||
# ORDER BY are the same for all statements. FORCE IDNEX and ORDER BY
|
# ORDER BY are the same for all statements. FORCE IDNEX and ORDER BY
|
||||||
# are needed to ensure deterministic nibbling.
|
# are needed to ensure deterministic nibbling.
|
||||||
|
|
||||||
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
|
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
|
||||||
my $order_by = join(', ', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum'
|
my $order_by = join(', ', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum' && $force_concat_enums
|
||||||
? "CONCAT(".$q->quote($_).")" : $q->quote($_)} @{$index_cols});
|
? "CONCAT(".$q->quote($_).")" : $q->quote($_)} @{$index_cols});
|
||||||
|
|
||||||
my $order_by_dec = join(' DESC,', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum'
|
my $order_by_dec = join(' DESC,', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum' && $force_concat_enums
|
||||||
? "CONCAT(".$q->quote($_).")" : $q->quote($_)} @{$index_cols});
|
? "CONCAT(".$q->quote($_).")" : $q->quote($_)} @{$index_cols});
|
||||||
|
|
||||||
# The real first row in the table. Usually we start nibbling from
|
# The real first row in the table. Usually we start nibbling from
|
||||||
|
@@ -38,6 +38,8 @@ my $dbh = $sb->get_dbh_for('master');
|
|||||||
|
|
||||||
if ( !$dbh ) {
|
if ( !$dbh ) {
|
||||||
plan skip_all => 'Cannot connect to sandbox master';
|
plan skip_all => 'Cannot connect to sandbox master';
|
||||||
|
} else {
|
||||||
|
plan tests => 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $q = new Quoter();
|
my $q = new Quoter();
|
||||||
@@ -879,7 +881,7 @@ is_deeply(
|
|||||||
# #############################################################################
|
# #############################################################################
|
||||||
|
|
||||||
diag(`/tmp/12345/use < $trunk/t/lib/samples/cardinality.sql >/dev/null`);
|
diag(`/tmp/12345/use < $trunk/t/lib/samples/cardinality.sql >/dev/null`);
|
||||||
|
$dbh->do('analyze table bad_tables.inv');
|
||||||
$ni = make_nibble_iter(
|
$ni = make_nibble_iter(
|
||||||
db => 'cardb',
|
db => 'cardb',
|
||||||
tbl => 't',
|
tbl => 't',
|
||||||
@@ -892,6 +894,56 @@ is(
|
|||||||
"Use non-unique index with highest cardinality (bug 1199591)"
|
"Use non-unique index with highest cardinality (bug 1199591)"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$sb->load_file('master', "t/lib/samples/NibbleIterator/enum_keys.sql");
|
||||||
|
$ni = undef;
|
||||||
|
eval {
|
||||||
|
$ni = make_nibble_iter(
|
||||||
|
db => 'test',
|
||||||
|
tbl => 't1',
|
||||||
|
argv => [qw(--databases test --chunk-size 3)],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
like(
|
||||||
|
$EVAL_ERROR,
|
||||||
|
qr/The index f3 in table `test`.`t1` has unsorted enum items/,
|
||||||
|
"PT-1572 Die on unsorted enum items in index",
|
||||||
|
);
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$ni = make_nibble_iter(
|
||||||
|
db => 'test',
|
||||||
|
tbl => 't1',
|
||||||
|
argv => [qw(--databases test --force-concat-enums --chunk-size 3)],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
like(
|
||||||
|
$ni->{explain_first_lb_sql},
|
||||||
|
qr/ORDER BY `f1`, `f2`, CONCAT\(`f3`\)/,
|
||||||
|
"PT-1572 Use of CONCAT for unsorted ENUM field items without --",
|
||||||
|
);
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$ni = make_nibble_iter(
|
||||||
|
db => 'test',
|
||||||
|
tbl => 't2',
|
||||||
|
argv => [qw(--databases test --chunk-size 3)],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
is(
|
||||||
|
$EVAL_ERROR,
|
||||||
|
'',
|
||||||
|
"PT-1572 No errors on sorted enum items in index",
|
||||||
|
);
|
||||||
|
|
||||||
|
like(
|
||||||
|
$ni->{explain_first_lb_sql},
|
||||||
|
qr/ORDER BY `f1`, `f2`, `f3`/,
|
||||||
|
"PT-1572 Don't use CONCAT for sorted ENUM field items without --force-concat-enums",
|
||||||
|
);
|
||||||
|
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
# Done.
|
# Done.
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
@@ -905,6 +957,7 @@ like(
|
|||||||
qr/Complete test coverage/,
|
qr/Complete test coverage/,
|
||||||
'_d() works'
|
'_d() works'
|
||||||
);
|
);
|
||||||
|
|
||||||
$sb->wipe_clean($dbh);
|
$sb->wipe_clean($dbh);
|
||||||
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
|
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
|
||||||
done_testing;
|
done_testing;
|
||||||
|
47
t/lib/samples/NibbleIterator/enum_keys.sql
Normal file
47
t/lib/samples/NibbleIterator/enum_keys.sql
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
DROP DATABASE IF EXISTS test;
|
||||||
|
CREATE DATABASE test;
|
||||||
|
USE test;
|
||||||
|
|
||||||
|
-- Don't change the comments. The enum word inside the comment is there to test the table parser
|
||||||
|
|
||||||
|
CREATE TABLE `test`.`t1` (
|
||||||
|
f1 DATE NOT NULL,
|
||||||
|
f2 INT(10) UNSIGNED NOT NULL,
|
||||||
|
f3 ENUM('c','a','b','d') NOT NULL DEFAULT 'c' COMMENT "unsorted enum items",
|
||||||
|
f4 INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`f1`,`f2`,`f3`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO `t1` VALUES
|
||||||
|
('2018-07-27',165910161,'c',1375471152),
|
||||||
|
('2018-07-27',393713658,'d',1382302491),
|
||||||
|
('2018-07-27',472875023,'c',525456967),
|
||||||
|
('2018-07-27',543582931,'c',1657080267),
|
||||||
|
('2018-07-27',583532949,'d',280366509),
|
||||||
|
('2018-07-27',1396416465,'d',1252007743),
|
||||||
|
('2018-07-27',1705409249,'c',1714682759),
|
||||||
|
('2018-07-27',1801160058,'a',1022430181),
|
||||||
|
('2018-07-27',1898674299,'c',1310715836),
|
||||||
|
('2018-07-27',2011751560,'a',109015753);
|
||||||
|
|
||||||
|
CREATE TABLE `test`.`t2` (
|
||||||
|
f1 DATE NOT NULL,
|
||||||
|
f2 INT(10) UNSIGNED NOT NULL,
|
||||||
|
f3 ENUM('a','b','c','d') NOT NULL DEFAULT 'c' COMMENT "sorted enum items",
|
||||||
|
f4 INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`f1`,`f2`,`f3`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO `t2` VALUES
|
||||||
|
('2018-07-27',165910161,'c',1375471152),
|
||||||
|
('2018-07-27',393713658,'d',1382302491),
|
||||||
|
('2018-07-27',472875023,'c',525456967),
|
||||||
|
('2018-07-27',543582931,'c',1657080267),
|
||||||
|
('2018-07-27',583532949,'d',280366509),
|
||||||
|
('2018-07-27',1396416465,'d',1252007743),
|
||||||
|
('2018-07-27',1705409249,'c',1714682759),
|
||||||
|
('2018-07-27',1801160058,'a',1022430181),
|
||||||
|
('2018-07-27',1898674299,'c',1310715836),
|
||||||
|
('2018-07-27',2011751560,'a',109015753);
|
Reference in New Issue
Block a user