mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-10 21:19:59 +00:00
Make NibbleIter query comments customizable. Update the module in pt-table-checksum and pt-osc.
This commit is contained in:
@@ -3907,6 +3907,16 @@ sub new {
|
||||
|
||||
my $nibble_params = can_nibble(%args);
|
||||
|
||||
my %comments = (
|
||||
bite => "bite table",
|
||||
nibble => "nibble table",
|
||||
);
|
||||
if ( $args{comments} ) {
|
||||
map { $comments{$_} = $args{comments}->{$_} }
|
||||
grep { defined $args{comments}->{$_} }
|
||||
keys %{$args{comments}};
|
||||
}
|
||||
|
||||
my $where = $o->has('where') ? $o->get('where') : '';
|
||||
my $tbl_struct = $tbl->{tbl_struct};
|
||||
my $ignore_col = $o->has('ignore-columns')
|
||||
@@ -3924,7 +3934,7 @@ sub new {
|
||||
: join(', ', map { $q->quote($_) } @cols))
|
||||
. " FROM $tbl->{name}"
|
||||
. ($where ? " WHERE $where" : '')
|
||||
. " /*checksum table*/";
|
||||
. " /*$comments{bite}*/";
|
||||
PTDEBUG && _d('One nibble statement:', $nibble_sql);
|
||||
|
||||
my $explain_nibble_sql
|
||||
@@ -3933,7 +3943,7 @@ sub new {
|
||||
: join(', ', map { $q->quote($_) } @cols))
|
||||
. " FROM $tbl->{name}"
|
||||
. ($where ? " WHERE $where" : '')
|
||||
. " /*explain checksum table*/";
|
||||
. " /*explain $comments{bite}*/";
|
||||
PTDEBUG && _d('Explain one nibble statement:', $explain_nibble_sql);
|
||||
|
||||
$self = {
|
||||
@@ -4015,9 +4025,7 @@ sub new {
|
||||
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
|
||||
. ($where ? " AND ($where)" : '')
|
||||
. ($args{order_by} ? " ORDER BY $order_by" : "")
|
||||
. " /*checksum chunk*/";
|
||||
# BARON: the above "checksum chunk" looks like this module isn't
|
||||
# genericized for use outside of pt-table-checksum.
|
||||
. " /*$comments{nibble}*/";
|
||||
PTDEBUG && _d('Nibble statement:', $nibble_sql);
|
||||
|
||||
my $explain_nibble_sql
|
||||
@@ -4029,7 +4037,7 @@ sub new {
|
||||
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
|
||||
. ($where ? " AND ($where)" : '')
|
||||
. ($args{order_by} ? " ORDER BY $order_by" : "")
|
||||
. " /*explain checksum chunk*/";
|
||||
. " /*explain $comments{nibble}*/";
|
||||
PTDEBUG && _d('Explain nibble statement:', $explain_nibble_sql);
|
||||
|
||||
my $limit = $chunk_size - 1;
|
||||
@@ -4867,8 +4875,6 @@ sub main {
|
||||
}
|
||||
}
|
||||
|
||||
# BARON: we should check that this option has a legal value. (Is this
|
||||
# something we should add to OptionParser?)
|
||||
my $rename_fk_method = lc($o->get('update-foreign-keys-method') || '');
|
||||
if ( $rename_fk_method eq 'drop_old_table' ) {
|
||||
$o->set('swap-tables', 0);
|
||||
@@ -4925,7 +4931,8 @@ sub main {
|
||||
$o->save_error("--find-child-tables requires --update-foreign-keys-method");
|
||||
}
|
||||
|
||||
# BARON: oh, I see you do it here.
|
||||
# See the "pod-based-option-value-validation" spec for how this may
|
||||
# be automagically validated.
|
||||
if ( $rename_fk_method
|
||||
&& $rename_fk_method ne 'rebuild_constraints'
|
||||
&& $rename_fk_method ne 'drop_old_table' ) {
|
||||
@@ -5628,6 +5635,10 @@ sub main {
|
||||
Quoter => $q,
|
||||
TableParser => $tp,
|
||||
TableNibbler => new TableNibbler(TableParser => $tp, Quoter => $q),
|
||||
comments => {
|
||||
bite => "pt-online-schema-change $PID copy table",
|
||||
nibble => "pt-online-schema-change $PID copy nibble",
|
||||
},
|
||||
);
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
|
@@ -3528,47 +3528,45 @@ sub new {
|
||||
}
|
||||
my ($cxn, $tbl, $chunk_size, $o, $q) = @args{@required_args};
|
||||
|
||||
my $where = $o->get('where');
|
||||
my ($row_est, $mysql_index) = get_row_estimate(%args, where => $where);
|
||||
my $one_nibble = !defined $args{one_nibble} || $args{one_nibble}
|
||||
? $row_est <= $chunk_size * $o->get('chunk-size-limit')
|
||||
: 0;
|
||||
PTDEBUG && _d('One nibble:', $one_nibble ? 'yes' : 'no');
|
||||
my $nibble_params = can_nibble(%args);
|
||||
|
||||
if ( $args{resume}
|
||||
&& !defined $args{resume}->{lower_boundary}
|
||||
&& !defined $args{resume}->{upper_boundary} ) {
|
||||
PTDEBUG && _d('Resuming from one nibble table');
|
||||
$one_nibble = 1;
|
||||
}
|
||||
|
||||
my $index = _find_best_index(%args, mysql_index => $mysql_index);
|
||||
if ( !$index && !$one_nibble ) {
|
||||
die "There is no good index and the table is oversized.";
|
||||
my %comments = (
|
||||
bite => "bite table",
|
||||
nibble => "nibble table",
|
||||
);
|
||||
if ( $args{comments} ) {
|
||||
map { $comments{$_} = $args{comments}->{$_} }
|
||||
grep { defined $args{comments}->{$_} }
|
||||
keys %{$args{comments}};
|
||||
}
|
||||
|
||||
my $where = $o->has('where') ? $o->get('where') : '';
|
||||
my $tbl_struct = $tbl->{tbl_struct};
|
||||
my $ignore_col = $o->get('ignore-columns') || {};
|
||||
my $all_cols = $o->get('columns') || $tbl_struct->{cols};
|
||||
my $ignore_col = $o->has('ignore-columns')
|
||||
? ($o->get('ignore-columns') || {})
|
||||
: {};
|
||||
my $all_cols = $o->has('columns')
|
||||
? ($o->get('columns') || $tbl_struct->{cols})
|
||||
: $tbl_struct->{cols};
|
||||
my @cols = grep { !$ignore_col->{$_} } @$all_cols;
|
||||
my $self;
|
||||
if ( $one_nibble ) {
|
||||
if ( $nibble_params->{one_nibble} ) {
|
||||
my $nibble_sql
|
||||
= ($args{dml} ? "$args{dml} " : "SELECT ")
|
||||
. ($args{select} ? $args{select}
|
||||
: join(', ', map { $q->quote($_) } @cols))
|
||||
. " FROM " . $q->quote(@{$tbl}{qw(db tbl)})
|
||||
. " FROM $tbl->{name}"
|
||||
. ($where ? " WHERE $where" : '')
|
||||
. " /*checksum table*/";
|
||||
. " /*$comments{bite}*/";
|
||||
PTDEBUG && _d('One nibble statement:', $nibble_sql);
|
||||
|
||||
my $explain_nibble_sql
|
||||
= "EXPLAIN SELECT "
|
||||
. ($args{select} ? $args{select}
|
||||
: join(', ', map { $q->quote($_) } @cols))
|
||||
. " FROM " . $q->quote(@{$tbl}{qw(db tbl)})
|
||||
. " FROM $tbl->{name}"
|
||||
. ($where ? " WHERE $where" : '')
|
||||
. " /*explain checksum table*/";
|
||||
. " /*explain $comments{bite}*/";
|
||||
PTDEBUG && _d('Explain one nibble statement:', $explain_nibble_sql);
|
||||
|
||||
$self = {
|
||||
@@ -3580,6 +3578,7 @@ sub new {
|
||||
};
|
||||
}
|
||||
else {
|
||||
my $index = $nibble_params->{index}; # brevity
|
||||
my $index_cols = $tbl->{tbl_struct}->{keys}->{$index}->{cols};
|
||||
|
||||
my $asc = $args{TableNibbler}->generate_asc_stmt(
|
||||
@@ -3591,7 +3590,7 @@ sub new {
|
||||
);
|
||||
PTDEBUG && _d('Ascend params:', Dumper($asc));
|
||||
|
||||
my $from = $q->quote(@{$tbl}{qw(db tbl)}) . " FORCE INDEX(`$index`)";
|
||||
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
|
||||
my $order_by = join(', ', map {$q->quote($_)} @{$index_cols});
|
||||
|
||||
my $first_lb_sql
|
||||
@@ -3649,7 +3648,7 @@ sub new {
|
||||
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
|
||||
. ($where ? " AND ($where)" : '')
|
||||
. ($args{order_by} ? " ORDER BY $order_by" : "")
|
||||
. " /*checksum chunk*/";
|
||||
. " /*$comments{nibble}*/";
|
||||
PTDEBUG && _d('Nibble statement:', $nibble_sql);
|
||||
|
||||
my $explain_nibble_sql
|
||||
@@ -3661,7 +3660,7 @@ sub new {
|
||||
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
|
||||
. ($where ? " AND ($where)" : '')
|
||||
. ($args{order_by} ? " ORDER BY $order_by" : "")
|
||||
. " /*explain checksum chunk*/";
|
||||
. " /*explain $comments{nibble}*/";
|
||||
PTDEBUG && _d('Explain nibble statement:', $explain_nibble_sql);
|
||||
|
||||
my $limit = $chunk_size - 1;
|
||||
@@ -3688,7 +3687,7 @@ sub new {
|
||||
};
|
||||
}
|
||||
|
||||
$self->{row_est} = $row_est;
|
||||
$self->{row_est} = $nibble_params->{row_est},
|
||||
$self->{nibbleno} = 0;
|
||||
$self->{have_rows} = 0;
|
||||
$self->{rowno} = 0;
|
||||
@@ -3851,6 +3850,44 @@ sub row_estimate {
|
||||
return $self->{row_est};
|
||||
}
|
||||
|
||||
sub can_nibble {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(Cxn tbl chunk_size OptionParser TableParser);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
my ($cxn, $tbl, $chunk_size, $o) = @args{@required_args};
|
||||
|
||||
my ($row_est, $mysql_index) = get_row_estimate(
|
||||
Cxn => $cxn,
|
||||
tbl => $tbl,
|
||||
where => $o->has('where') ? $o->get('where') : '',
|
||||
);
|
||||
|
||||
my $one_nibble = !defined $args{one_nibble} || $args{one_nibble}
|
||||
? $row_est <= $chunk_size * $o->get('chunk-size-limit')
|
||||
: 0;
|
||||
PTDEBUG && _d('One nibble:', $one_nibble ? 'yes' : 'no');
|
||||
|
||||
if ( $args{resume}
|
||||
&& !defined $args{resume}->{lower_boundary}
|
||||
&& !defined $args{resume}->{upper_boundary} ) {
|
||||
PTDEBUG && _d('Resuming from one nibble table');
|
||||
$one_nibble = 1;
|
||||
}
|
||||
|
||||
my $index = _find_best_index(%args, mysql_index => $mysql_index);
|
||||
if ( !$index && !$one_nibble ) {
|
||||
die "There is no good index and the table is oversized.";
|
||||
}
|
||||
|
||||
return {
|
||||
row_est => $row_est, # nibble about this many rows
|
||||
index => $index, # using this index
|
||||
one_nibble => $one_nibble, # if the table fits in one nibble/chunk
|
||||
};
|
||||
}
|
||||
|
||||
sub _find_best_index {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(Cxn tbl TableParser);
|
||||
@@ -3924,10 +3961,10 @@ sub _find_best_index {
|
||||
|
||||
sub _get_index_cardinality {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(Cxn tbl index Quoter);
|
||||
my ($cxn, $tbl, $index, $q) = @args{@required_args};
|
||||
my @required_args = qw(Cxn tbl index);
|
||||
my ($cxn, $tbl, $index) = @args{@required_args};
|
||||
|
||||
my $sql = "SHOW INDEXES FROM " . $q->quote(@{$tbl}{qw(db tbl)})
|
||||
my $sql = "SHOW INDEXES FROM $tbl->{name} "
|
||||
. "WHERE Key_name = '$index'";
|
||||
PTDEBUG && _d($sql);
|
||||
my $cardinality = 1;
|
||||
@@ -3941,22 +3978,25 @@ sub _get_index_cardinality {
|
||||
|
||||
sub get_row_estimate {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(Cxn tbl OptionParser TableParser Quoter);
|
||||
my ($cxn, $tbl, $o, $tp, $q) = @args{@required_args};
|
||||
my @required_args = qw(Cxn tbl);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
my ($cxn, $tbl) = @args{@required_args};
|
||||
|
||||
if ( $args{where} ) {
|
||||
PTDEBUG && _d('WHERE clause, using explain plan for row estimate');
|
||||
my $table = $q->quote(@{$tbl}{qw(db tbl)});
|
||||
my $sql = "EXPLAIN SELECT * FROM $table WHERE $args{where}";
|
||||
if ( !$args{where} && exists $tbl->{tbl_status} ) {
|
||||
PTDEBUG && _d('Using table status for row estimate');
|
||||
return $tbl->{tbl_status}->{rows} || 0;
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Use EXPLAIN for row estimate');
|
||||
my $sql = "EXPLAIN SELECT * FROM $tbl->{name} "
|
||||
. "WHERE " . ($args{where} || '1=1');
|
||||
PTDEBUG && _d($sql);
|
||||
my $expl = $cxn->dbh()->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($expl));
|
||||
return ($expl->{rows} || 0), $expl->{key};
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('No WHERE clause, using table status for row estimate');
|
||||
return $tbl->{tbl_status}->{rows} || 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub _prepare_sths {
|
||||
@@ -4666,6 +4706,7 @@ sub next {
|
||||
|
||||
sub _iterate_files {
|
||||
my ( $self ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
|
||||
if ( !$self->{fh} ) {
|
||||
my ($fh, $file) = $self->{file_itr}->();
|
||||
@@ -4715,6 +4756,7 @@ sub _iterate_files {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $q->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
};
|
||||
}
|
||||
@@ -4792,6 +4834,7 @@ sub _iterate_dbh {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $q->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_status => $tbl_status,
|
||||
};
|
||||
@@ -6745,6 +6788,10 @@ sub main {
|
||||
TableNibbler => $tn,
|
||||
TableParser => $tp,
|
||||
RowChecksum => $rc,
|
||||
comments => {
|
||||
bite => "checksum table",
|
||||
nibble => "checksum chunk",
|
||||
},
|
||||
);
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
|
@@ -66,6 +66,18 @@ sub new {
|
||||
# and if table can be nibbled in one chunk.
|
||||
my $nibble_params = can_nibble(%args);
|
||||
|
||||
# Text appended to the queries in comments so caller can identify
|
||||
# them in processlist, binlog, etc.
|
||||
my %comments = (
|
||||
bite => "bite table",
|
||||
nibble => "nibble table",
|
||||
);
|
||||
if ( $args{comments} ) {
|
||||
map { $comments{$_} = $args{comments}->{$_} }
|
||||
grep { defined $args{comments}->{$_} }
|
||||
keys %{$args{comments}};
|
||||
}
|
||||
|
||||
my $where = $o->has('where') ? $o->get('where') : '';
|
||||
my $tbl_struct = $tbl->{tbl_struct};
|
||||
my $ignore_col = $o->has('ignore-columns')
|
||||
@@ -85,7 +97,7 @@ sub new {
|
||||
: join(', ', map { $q->quote($_) } @cols))
|
||||
. " FROM $tbl->{name}"
|
||||
. ($where ? " WHERE $where" : '')
|
||||
. " /*checksum table*/";
|
||||
. " /*$comments{bite}*/";
|
||||
PTDEBUG && _d('One nibble statement:', $nibble_sql);
|
||||
|
||||
my $explain_nibble_sql
|
||||
@@ -94,7 +106,7 @@ sub new {
|
||||
: join(', ', map { $q->quote($_) } @cols))
|
||||
. " FROM $tbl->{name}"
|
||||
. ($where ? " WHERE $where" : '')
|
||||
. " /*explain checksum table*/";
|
||||
. " /*explain $comments{bite}*/";
|
||||
PTDEBUG && _d('Explain one nibble statement:', $explain_nibble_sql);
|
||||
|
||||
$self = {
|
||||
@@ -197,7 +209,7 @@ sub new {
|
||||
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
|
||||
. ($where ? " AND ($where)" : '')
|
||||
. ($args{order_by} ? " ORDER BY $order_by" : "")
|
||||
. " /*checksum chunk*/";
|
||||
. " /*$comments{nibble}*/";
|
||||
PTDEBUG && _d('Nibble statement:', $nibble_sql);
|
||||
|
||||
my $explain_nibble_sql
|
||||
@@ -209,7 +221,7 @@ sub new {
|
||||
. " AND " . $asc->{boundaries}->{'<='} # upper boundary
|
||||
. ($where ? " AND ($where)" : '')
|
||||
. ($args{order_by} ? " ORDER BY $order_by" : "")
|
||||
. " /*explain checksum chunk*/";
|
||||
. " /*explain $comments{nibble}*/";
|
||||
PTDEBUG && _d('Explain nibble statement:', $explain_nibble_sql);
|
||||
|
||||
my $limit = $chunk_size - 1;
|
||||
|
@@ -39,7 +39,7 @@ if ( !$dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox master';
|
||||
}
|
||||
else {
|
||||
plan tests => 46;
|
||||
plan tests => 48;
|
||||
}
|
||||
|
||||
my $q = new Quoter();
|
||||
@@ -94,6 +94,7 @@ sub make_nibble_iter {
|
||||
one_nibble => $args{one_nibble},
|
||||
resume => $args{resume},
|
||||
order_by => $args{order_by},
|
||||
comments => $args{comments},
|
||||
%common_modules,
|
||||
);
|
||||
|
||||
@@ -527,7 +528,7 @@ $ni = make_nibble_iter(
|
||||
$ni->next();
|
||||
is(
|
||||
$ni->statements()->{nibble}->{Statement},
|
||||
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code` FROM `sakila`.`address` FORCE INDEX(`PRIMARY`) WHERE ((`address_id` >= ?)) AND ((`address_id` <= ?)) /*checksum chunk*/",
|
||||
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code` FROM `sakila`.`address` FORCE INDEX(`PRIMARY`) WHERE ((`address_id` >= ?)) AND ((`address_id` <= ?)) /*nibble table*/",
|
||||
"--ignore-columns"
|
||||
);
|
||||
|
||||
@@ -545,7 +546,7 @@ $ni->next();
|
||||
|
||||
is(
|
||||
$ni->statements()->{nibble}->{Statement},
|
||||
"SELECT `actor_id`, `film_id`, `last_update` FROM `sakila`.`film_actor` FORCE INDEX(`PRIMARY`) WHERE ((`actor_id` > ?) OR (`actor_id` = ? AND `film_id` >= ?)) AND ((`actor_id` < ?) OR (`actor_id` = ? AND `film_id` <= ?)) ORDER BY `actor_id`, `film_id` /*checksum chunk*/",
|
||||
"SELECT `actor_id`, `film_id`, `last_update` FROM `sakila`.`film_actor` FORCE INDEX(`PRIMARY`) WHERE ((`actor_id` > ?) OR (`actor_id` = ? AND `film_id` >= ?)) AND ((`actor_id` < ?) OR (`actor_id` = ? AND `film_id` <= ?)) ORDER BY `actor_id`, `film_id` /*nibble table*/",
|
||||
"Add ORDER BY to nibble SQL"
|
||||
);
|
||||
|
||||
@@ -722,7 +723,7 @@ $ni = make_nibble_iter(
|
||||
my $sql = $ni->statements()->{nibble}->{Statement};
|
||||
is(
|
||||
$sql,
|
||||
"SELECT `c` FROM `test`.`t` WHERE c>'m' /*checksum table*/",
|
||||
"SELECT `c` FROM `test`.`t` WHERE c>'m' /*bite table*/",
|
||||
"One nibble SQL with where"
|
||||
);
|
||||
|
||||
@@ -795,6 +796,43 @@ is_deeply(
|
||||
"Resume from end"
|
||||
);
|
||||
|
||||
# #############################################################################
|
||||
# Customize bite and nibble statement comments.
|
||||
# #############################################################################
|
||||
$ni = make_nibble_iter(
|
||||
db => 'sakila',
|
||||
tbl => 'address',
|
||||
argv => [qw(--tables sakila.address --chunk-size 10)],
|
||||
comments => {
|
||||
bite => "my bite",
|
||||
nibble => "my nibble",
|
||||
}
|
||||
);
|
||||
|
||||
$ni->next();
|
||||
is(
|
||||
$ni->statements()->{nibble}->{Statement},
|
||||
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code`, `phone`, `last_update` FROM `sakila`.`address` FORCE INDEX(`PRIMARY`) WHERE ((`address_id` >= ?)) AND ((`address_id` <= ?)) /*my nibble*/",
|
||||
"Custom nibble comment"
|
||||
);
|
||||
|
||||
$ni = make_nibble_iter(
|
||||
db => 'sakila',
|
||||
tbl => 'address',
|
||||
argv => [qw(--tables sakila.address --chunk-size 1000)],
|
||||
comments => {
|
||||
bite => "my bite",
|
||||
nibble => "my nibble",
|
||||
}
|
||||
);
|
||||
|
||||
$ni->next();
|
||||
is(
|
||||
$ni->statements()->{nibble}->{Statement},
|
||||
"SELECT `address_id`, `address`, `address2`, `district`, `city_id`, `postal_code`, `phone`, `last_update` FROM `sakila`.`address` /*my bite*/",
|
||||
"Custom bite comment"
|
||||
);
|
||||
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
|
Reference in New Issue
Block a user