mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-21 19:34:52 +00:00
Merge with Baron's doc branch https://code.launchpad.net/~percona-toolkit-dev/percona-toolkit/pt-query-advisor-docs
This commit is contained in:
@@ -6847,17 +6847,12 @@ pt-query-advisor - Analyze queries and advise on possible problems.
|
||||
|
||||
Usage: pt-query-advisor [OPTION...] [FILE]
|
||||
|
||||
pt-query-advisor analyzes queries and advises on possible problems.
|
||||
Queries are given either by specifying slowlog files, --query, or --review.
|
||||
pt-query-advisor detects bad patterns in a SQL query from the text alone.
|
||||
|
||||
Analyze all queries in a slow log:
|
||||
Analyze all queries in a log in MySQL's slow query log format:
|
||||
|
||||
pt-query-advisor /path/to/slow-query.log
|
||||
|
||||
Analyze all queires in a general log:
|
||||
|
||||
pt-query-advisor --type genlog mysql.log
|
||||
|
||||
Get queries from tcpdump using pt-query-digest:
|
||||
|
||||
pt-query-digest --type tcpdump.txt --print --no-report | pt-query-advisor
|
||||
@@ -6872,8 +6867,7 @@ tools) and those created by bugs.
|
||||
pt-query-advisor simply reads queries and examines them, and is thus
|
||||
very low risk.
|
||||
|
||||
At the time of this release there is a bug that may cause an infinite (or
|
||||
very long) loop when parsing very large queries.
|
||||
At the time of this release there are no known bugs that could harm users.
|
||||
|
||||
The authoritative source for updated information is always the online issue
|
||||
tracking system. Issues that affect this tool will be marked as such. You can
|
||||
@@ -6958,14 +6952,16 @@ wildcard is potentially a bug in the SQL.
|
||||
|
||||
severity: warn
|
||||
|
||||
SELECT without WHERE. The SELECT statement has no WHERE clause.
|
||||
SELECT without WHERE. The SELECT statement has no WHERE clause and could
|
||||
examine many more rows than intended.
|
||||
|
||||
=item CLA.002
|
||||
|
||||
severity: note
|
||||
|
||||
ORDER BY RAND(). ORDER BY RAND() is a very inefficient way to
|
||||
retrieve a random row from the results.
|
||||
retrieve a random row from the results, because it sorts the entire result
|
||||
and then throws most of it away.
|
||||
|
||||
=item CLA.003
|
||||
|
||||
@@ -6973,7 +6969,8 @@ severity: note
|
||||
|
||||
LIMIT with OFFSET. Paginating a result set with LIMIT and OFFSET is
|
||||
O(n^2) complexity, and will cause performance problems as the data
|
||||
grows larger.
|
||||
grows larger. Pagination techniques such as bookmarked scans are much more
|
||||
efficient.
|
||||
|
||||
=item CLA.004
|
||||
|
||||
@@ -6987,21 +6984,24 @@ query is changed.
|
||||
|
||||
severity: warn
|
||||
|
||||
ORDER BY constant column.
|
||||
ORDER BY constant column. This is probably a bug in your SQL; at best it is a
|
||||
useless operation that does not change the query results.
|
||||
|
||||
=item CLA.006
|
||||
|
||||
severity: warn
|
||||
|
||||
GROUP BY or ORDER BY different tables will force a temp table and filesort.
|
||||
GROUP BY or ORDER BY on different tables. This will force the use of a temporary
|
||||
table and filesort, which can be a huge performance problem and can consume
|
||||
large amounts of memory and temporary space on disk.
|
||||
|
||||
=item CLA.007
|
||||
|
||||
severity: warn
|
||||
|
||||
ORDER BY different directions prevents index from being used. All tables
|
||||
in the ORDER BY clause must be either ASC or DESC, else MySQL cannot use
|
||||
an index.
|
||||
ORDER BY different directions. All tables in the ORDER BY clause must be in the
|
||||
same direction, either ASC or DESC, or MySQL cannot use an index to avoid a sort
|
||||
after generating results.
|
||||
|
||||
=item COL.001
|
||||
|
||||
@@ -7033,8 +7033,9 @@ more efficient to store IP addresses as integers.
|
||||
|
||||
severity: warn
|
||||
|
||||
Unquoted date/time literal. A query such as "WHERE col<2010-02-12"
|
||||
is valid SQL but is probably a bug; the literal should be quoted.
|
||||
Unquoted date/time literal. A query such as "WHERE col<2010-02-12" is valid SQL
|
||||
but is probably a bug, because it will be interpreted as "WHERE col<1996"; the
|
||||
literal should be quoted.
|
||||
|
||||
=item KWR.001
|
||||
|
||||
@@ -7049,23 +7050,25 @@ result screens.
|
||||
|
||||
severity: crit
|
||||
|
||||
Mixing comma and ANSI joins. Mixing comma joins and ANSI joins
|
||||
is confusing to humans, and the behavior differs between some
|
||||
MySQL versions.
|
||||
Mixing comma and ANSI joins. Mixing comma joins and ANSI joins is confusing to
|
||||
humans, and the behavior and precedence differs between some MySQL versions,
|
||||
which can introduce bugs.
|
||||
|
||||
=item JOI.002
|
||||
|
||||
severity: crit
|
||||
|
||||
A table is joined twice. The same table appears at least twice in the
|
||||
FROM clause.
|
||||
FROM clause in a manner that can be reduced to a single access to the table.
|
||||
|
||||
=item JOI.003
|
||||
|
||||
severity: warn
|
||||
|
||||
Reference to outer table column in WHERE clause prevents OUTER JOIN,
|
||||
implicitly converts to INNER JOIN.
|
||||
OUTER JOIN defeated. The reference to an outer table column in the WHERE clause
|
||||
prevents the OUTER JOIN from returning any non-matched rows, which implicitly
|
||||
converts the query to an INNER JOIN. This is probably a bug in the query or a
|
||||
misunderstanding of how OUTER JOIN works.
|
||||
|
||||
=item JOI.004
|
||||
|
||||
@@ -7096,7 +7099,8 @@ non-deterministic results, depending on the query execution plan.
|
||||
|
||||
severity: note
|
||||
|
||||
!= is non-standard. Use the <> operator to test for inequality.
|
||||
The != operator is non-standard. Use the <> operator to test for inequality
|
||||
instead.
|
||||
|
||||
=item SUB.001
|
||||
|
||||
@@ -7104,9 +7108,8 @@ severity: crit
|
||||
|
||||
IN() and NOT IN() subqueries are poorly optimized. MySQL executes the subquery
|
||||
as a dependent subquery for each row in the outer query. This is a frequent
|
||||
cause of serious performance problems. This might change version 6.0 of MySQL,
|
||||
but for versions 5.1 and older, the query should be rewritten as a JOIN or a
|
||||
LEFT OUTER JOIN, respectively.
|
||||
cause of serious performance problems in MySQL 5.5 and older versions. The
|
||||
query probably should be rewritten as a JOIN or a LEFT OUTER JOIN, respectively.
|
||||
|
||||
=back
|
||||
|
||||
|
@@ -3778,7 +3778,7 @@ sub set_nibble_number {
|
||||
|
||||
sub nibble_index {
|
||||
my ($self) = @_;
|
||||
return lc($self->{index});
|
||||
return $self->{index};
|
||||
}
|
||||
|
||||
sub statements {
|
||||
@@ -5877,17 +5877,20 @@ sub main {
|
||||
# ########################################################################
|
||||
# Connect to the master.
|
||||
# ########################################################################
|
||||
my $vp = new VersionParser();
|
||||
|
||||
my $set_on_connect = sub {
|
||||
my ($dbh) = @_;
|
||||
|
||||
return if $o->get('explain');
|
||||
my $sql;
|
||||
|
||||
# https://bugs.launchpad.net/percona-toolkit/+bug/919352
|
||||
# The tool shouldn't blindly attempt to change binlog_format;
|
||||
# instead, it should check if it's already set to STATEMENT.
|
||||
# This is becase starting with MySQL 5.1.29, changing the format
|
||||
# requires a SUPER user.
|
||||
my $sql = 'SELECT @@binlog_format';
|
||||
if ( $vp->version_ge($dbh, '5.1.5') ) {
|
||||
$sql = 'SELECT @@binlog_format';
|
||||
PTDEBUG && _d($dbh, $sql);
|
||||
my ($original_binlog_format) = $dbh->selectrow_array($sql);
|
||||
PTDEBUG && _d('Original binlog_format:', $original_binlog_format);
|
||||
@@ -5908,6 +5911,7 @@ sub main {
|
||||
. "before running this tool.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Set transaction isolation level. We set binlog_format to STATEMENT,
|
||||
# but if the transaction isolation level is set to READ COMMITTED and the
|
||||
@@ -5995,7 +5999,6 @@ sub main {
|
||||
my $q = new Quoter();
|
||||
my $tp = new TableParser(Quoter => $q);
|
||||
my $rc = new RowChecksum(Quoter=> $q, OptionParser => $o);
|
||||
my $vp = new VersionParser();
|
||||
my $ms = new MasterSlave(VersionParser => $vp);
|
||||
|
||||
my $slaves; # all slaves (that we can find)
|
||||
@@ -6399,7 +6402,8 @@ sub main {
|
||||
sth => $sth->{explain_upper_boundary},
|
||||
vals => [ @{$boundary->{lower}}, $nibble_iter->chunk_size() ],
|
||||
);
|
||||
if ( lc($expl->{key} || '') ne $nibble_iter->nibble_index() ) {
|
||||
if ( lc($expl->{key} || '')
|
||||
ne lc($nibble_iter->nibble_index() || '') ) {
|
||||
PTDEBUG && _d('Cannot nibble next chunk, aborting table');
|
||||
if ( $o->get('quiet') < 2 ) {
|
||||
my $msg
|
||||
@@ -6467,7 +6471,8 @@ sub main {
|
||||
: 0;
|
||||
|
||||
# Ensure that MySQL is using the chunk index.
|
||||
if ( lc($expl->{key} || '') ne $nibble_iter->nibble_index() ) {
|
||||
if ( lc($expl->{key} || '')
|
||||
ne lc($nibble_iter->nibble_index() || '') ) {
|
||||
PTDEBUG && _d('Chunk', $args{nibbleno}, 'of table',
|
||||
"$tbl->{db}.$tbl->{tbl} not using chunk index, skipping");
|
||||
return 0; # next boundary
|
||||
@@ -7266,7 +7271,7 @@ sub have_more_chunks {
|
||||
|
||||
# The previous chunk index must match the current chunk index,
|
||||
# else we don't know what to do.
|
||||
my $chunk_index = $nibble_iter->nibble_index() || '';
|
||||
my $chunk_index = lc($nibble_iter->nibble_index() || '');
|
||||
if (lc($last_chunk->{chunk_index} || '') ne $chunk_index) {
|
||||
warn ts("Cannot resume from table $tbl->{db}.$tbl->{tbl} chunk "
|
||||
. "$last_chunk->{chunk} because the chunk indexes are different: "
|
||||
|
@@ -347,7 +347,7 @@ sub set_nibble_number {
|
||||
|
||||
sub nibble_index {
|
||||
my ($self) = @_;
|
||||
return lc($self->{index});
|
||||
return $self->{index};
|
||||
}
|
||||
|
||||
sub statements {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
Differences on h=127.0.0.1,P=12346
|
||||
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
|
||||
sakila.city 1 0 1 primary 1 100
|
||||
sakila.city 6 0 1 primary 501 600
|
||||
sakila.city 1 0 1 PRIMARY 1 100
|
||||
sakila.city 6 0 1 PRIMARY 501 600
|
||||
|
||||
Differences on h=127.0.0.1,P=12347
|
||||
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
|
||||
sakila.city 1 0 1 primary 1 100
|
||||
sakila.city 6 0 1 primary 501 600
|
||||
sakila.city 1 0 1 PRIMARY 1 100
|
||||
sakila.city 6 0 1 PRIMARY 501 600
|
||||
|
||||
|
@@ -28,7 +28,7 @@ elsif ( !$slave_dbh ) {
|
||||
plan skip_all => 'Cannot connect to sandbox slave';
|
||||
}
|
||||
else {
|
||||
plan tests => 19;
|
||||
plan tests => 21;
|
||||
}
|
||||
|
||||
$sb->wipe_clean($master_dbh);
|
||||
@@ -198,6 +198,41 @@ is(
|
||||
"Synced diff (bug 911996)"
|
||||
);
|
||||
|
||||
# Fix bug 927771.
|
||||
$sb->load_file('master', 't/pt-table-sync/samples/bug_927771.sql');
|
||||
PerconaTest::wait_for_table($slave_dbh, "test.t", "c='j'");
|
||||
|
||||
$slave_dbh->do("update test.t set c='z' where id>8");
|
||||
|
||||
`$trunk/bin/pt-table-checksum h=127.1,P=12345,u=msandbox,p=msandbox --max-load '' --lock-wait 3 --chunk-size 2 -t test.t --quiet`;
|
||||
|
||||
PerconaTest::wait_for_table($slave_dbh, "percona.checksums", "db='test' and tbl='t' and chunk=4");
|
||||
|
||||
$output = output(
|
||||
sub {
|
||||
pt_table_sync::main('h=127.1,P=12345,u=msandbox,p=msandbox',
|
||||
qw(--print --execute --replicate percona.checksums),
|
||||
qw(--no-foreign-key-checks))
|
||||
},
|
||||
stderr => 1,
|
||||
);
|
||||
|
||||
like(
|
||||
$output,
|
||||
qr/REPLACE INTO `test`.`t`\(`id`, `c`\) VALUES \('9', 'i'\)/,
|
||||
"--replicate with uc index (bug 927771)"
|
||||
);
|
||||
|
||||
my $rows = $slave_dbh->selectall_arrayref("select id, c from test.t where id>8 order by id");
|
||||
is_deeply(
|
||||
$rows,
|
||||
[
|
||||
[9, 'i'],
|
||||
[10, 'j'],
|
||||
],
|
||||
"Synced slaved (bug 927771)"
|
||||
);
|
||||
|
||||
# #############################################################################
|
||||
# Done.
|
||||
# #############################################################################
|
||||
|
18
t/pt-table-sync/samples/bug_927771.sql
Normal file
18
t/pt-table-sync/samples/bug_927771.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
drop database if exists test;
|
||||
create database test;
|
||||
use test;
|
||||
create table t (
|
||||
id int auto_increment not null primary key,
|
||||
c varchar(8) not null
|
||||
) engine=innodb;
|
||||
insert into test.t values
|
||||
(null, 'a'),
|
||||
(null, 'b'),
|
||||
(null, 'c'),
|
||||
(null, 'd'),
|
||||
(null, 'e'),
|
||||
(null, 'f'),
|
||||
(null, 'g'),
|
||||
(null, 'h'),
|
||||
(null, 'i'),
|
||||
(null, 'j');
|
Reference in New Issue
Block a user