mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
MDEV-6714 mysqldump slow with tables in big databases
mysqldump now attempts to make use of the INFORMATION_SCHEMA tables. If the table name is not found with a case sensitive search, it fallbacks to a case insensitive search.
This commit is contained in:
parent
c6b4212821
commit
ae4b24340d
1 changed files with 115 additions and 24 deletions
|
@ -1735,11 +1735,11 @@ static my_bool test_if_special_chars(const char *str)
|
|||
} /* test_if_special_chars */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
quote_name(name, buff, force)
|
||||
|
||||
Quotes char string, taking into account compatible mode
|
||||
Quotes a string, if it requires quoting. To force quoting regardless
|
||||
of the characters within the string, the force flag can be set to true.
|
||||
|
||||
Args
|
||||
|
||||
|
@ -1748,8 +1748,8 @@ static my_bool test_if_special_chars(const char *str)
|
|||
force Flag to make it ignore 'test_if_special_chars'
|
||||
|
||||
Returns
|
||||
|
||||
buff quoted string
|
||||
A pointer to the quoted string, or the original string if nothing has
|
||||
changed.
|
||||
|
||||
*/
|
||||
static char *quote_name(const char *name, char *buff, my_bool force)
|
||||
|
@ -1815,6 +1815,26 @@ static char *quote_for_like(const char *name, char *buff)
|
|||
return buff;
|
||||
}
|
||||
|
||||
static char *quote_for_equal(const char *name, char *buff)
|
||||
{
|
||||
char *to= buff;
|
||||
*to++= '\'';
|
||||
while (*name)
|
||||
{
|
||||
if (*name == '\\')
|
||||
{
|
||||
*to++='\\';
|
||||
}
|
||||
if (*name == '\'')
|
||||
*to++= '\\';
|
||||
*to++= *name++;
|
||||
}
|
||||
to[0]= '\'';
|
||||
to[1]= 0;
|
||||
return buff;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Quote and print a string.
|
||||
|
@ -3341,8 +3361,10 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
|
|||
/* Get list of triggers. */
|
||||
|
||||
my_snprintf(query_buff, sizeof(query_buff),
|
||||
"SHOW TRIGGERS LIKE %s",
|
||||
quote_for_like(table_name, name_buff));
|
||||
"SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS "
|
||||
"WHERE EVENT_OBJECT_SCHEMA = DATABASE() AND "
|
||||
"EVENT_OBJECT_TABLE = %s",
|
||||
quote_for_equal(table_name, name_buff));
|
||||
|
||||
if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff))
|
||||
goto done;
|
||||
|
@ -4695,29 +4717,37 @@ static my_bool dump_all_views_in_db(char *database)
|
|||
|
||||
|
||||
/*
|
||||
get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
|
||||
table name from the server for the table name given on the command line.
|
||||
we do this because the table name given on the command line may be a
|
||||
different case (e.g. T1 vs t1)
|
||||
|
||||
RETURN
|
||||
pointer to the table name
|
||||
0 if error
|
||||
See get_actual_table_name. Used to retrieve the correct table name
|
||||
from the database schema.
|
||||
*/
|
||||
|
||||
static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
|
||||
static char *get_actual_table_name_helper(const char *old_table_name,
|
||||
my_bool case_sensitive,
|
||||
MEM_ROOT *root)
|
||||
{
|
||||
char *name= 0;
|
||||
MYSQL_RES *table_res;
|
||||
MYSQL_ROW row;
|
||||
char query[50 + 2*NAME_LEN];
|
||||
char show_name_buff[FN_REFLEN];
|
||||
DBUG_ENTER("get_actual_table_name");
|
||||
DBUG_ENTER("get_actual_table_name_helper");
|
||||
|
||||
/* Check memory for quote_for_like() */
|
||||
DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
|
||||
my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
|
||||
quote_for_like(old_table_name, show_name_buff));
|
||||
|
||||
if (case_sensitive)
|
||||
{
|
||||
DBUG_PRINT("info", ("case sensitive search"));
|
||||
my_snprintf(query, sizeof(query),
|
||||
"SELECT table_name FROM INFORMATION_SCHEMA.TABLES "
|
||||
"WHERE table_schema = DATABASE() AND table_name = %s",
|
||||
quote_for_equal(old_table_name, show_name_buff));
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info", ("case insensitive search"));
|
||||
my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
|
||||
quote_for_like(old_table_name, show_name_buff));
|
||||
}
|
||||
|
||||
if (mysql_query_with_error_report(mysql, 0, query))
|
||||
return NullS;
|
||||
|
@ -4742,6 +4772,60 @@ static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
|
|||
DBUG_RETURN(name);
|
||||
}
|
||||
|
||||
/*
|
||||
get_actual_table_name -- executes a SELECT .. FROM I_S.tables to check
|
||||
if the table name given on the command line matches the one in the database.
|
||||
If the table is not found, it falls back to a slower SHOW TABLES LIKE '%s' to
|
||||
get the actual table name from the server.
|
||||
|
||||
We do this because the table name given on the command line may be a
|
||||
different case (e.g. T1 vs t1), but checking this takes a long time
|
||||
when there are many tables present.
|
||||
|
||||
RETURN
|
||||
pointer to the table name
|
||||
0 if error
|
||||
*/
|
||||
|
||||
static char *get_actual_table_name(const char *old_table_name,
|
||||
int lower_case_table_names,
|
||||
MEM_ROOT *root)
|
||||
{
|
||||
char *name= 0;
|
||||
DBUG_ENTER("get_actual_table_name");
|
||||
|
||||
name= get_actual_table_name_helper(old_table_name, TRUE, root);
|
||||
if (!name && !lower_case_table_names)
|
||||
name= get_actual_table_name_helper(old_table_name, FALSE, root);
|
||||
DBUG_RETURN(name);
|
||||
}
|
||||
|
||||
/*
|
||||
Retrieve the value for the server system variable lower_case_table_names.
|
||||
|
||||
RETURN
|
||||
0 case sensitive.
|
||||
> 0 case insensitive
|
||||
*/
|
||||
static int get_sys_var_lower_case_table_names()
|
||||
{
|
||||
int lower_case_table_names = 0;
|
||||
MYSQL_RES *table_res;
|
||||
MYSQL_ROW row;
|
||||
const char *show_var_query = "SHOW VARIABLES LIKE 'lower_case_table_names'";
|
||||
if (mysql_query_with_error_report(mysql, &table_res, show_var_query))
|
||||
return 0; /* In case of error, assume default value of 0 */
|
||||
|
||||
if ((row= mysql_fetch_row(table_res)))
|
||||
{
|
||||
lower_case_table_names= atoi(row[1]);
|
||||
mysql_free_result(table_res);
|
||||
}
|
||||
|
||||
return lower_case_table_names;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dump_selected_tables(char *db, char **table_names, int tables)
|
||||
{
|
||||
|
@ -4749,6 +4833,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
|
|||
DYNAMIC_STRING lock_tables_query;
|
||||
MEM_ROOT root;
|
||||
char **dump_tables, **pos, **end;
|
||||
int lower_case_table_names;
|
||||
DBUG_ENTER("dump_selected_tables");
|
||||
|
||||
if (init_dumping(db, init_dumping_tables))
|
||||
|
@ -4758,11 +4843,15 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
|
|||
if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
|
||||
die(EX_EOM, "alloc_root failure.");
|
||||
|
||||
/* Figure out how to compare table names. */
|
||||
lower_case_table_names = get_sys_var_lower_case_table_names();
|
||||
|
||||
init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
|
||||
for (; tables > 0 ; tables-- , table_names++)
|
||||
{
|
||||
/* the table name passed on commandline may be wrong case */
|
||||
if ((*pos= get_actual_table_name(*table_names, &root)))
|
||||
if ((*pos= get_actual_table_name(*table_names, lower_case_table_names,
|
||||
&root)))
|
||||
{
|
||||
/* Add found table name to lock_tables_query */
|
||||
if (lock_tables)
|
||||
|
@ -5369,8 +5458,10 @@ char check_if_ignore_table(const char *table_name, char *table_type)
|
|||
|
||||
/* Check memory for quote_for_like() */
|
||||
DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
|
||||
my_snprintf(buff, sizeof(buff), "show table status like %s",
|
||||
quote_for_like(table_name, show_name_buff));
|
||||
my_snprintf(buff, sizeof(buff),
|
||||
"SELECT engine FROM INFORMATION_SCHEMA.TABLES "
|
||||
"WHERE table_name = %s",
|
||||
quote_for_equal(table_name, show_name_buff));
|
||||
if (mysql_query_with_error_report(mysql, &res, buff))
|
||||
{
|
||||
if (mysql_errno(mysql) != ER_PARSE_ERROR)
|
||||
|
@ -5388,7 +5479,7 @@ char check_if_ignore_table(const char *table_name, char *table_type)
|
|||
mysql_free_result(res);
|
||||
DBUG_RETURN(result); /* assume table is ok */
|
||||
}
|
||||
if (!(row[1]))
|
||||
if (!(row[0]))
|
||||
strmake(table_type, "VIEW", NAME_LEN-1);
|
||||
else
|
||||
{
|
||||
|
@ -5398,7 +5489,7 @@ char check_if_ignore_table(const char *table_name, char *table_type)
|
|||
these types, but we do want to use delayed inserts in the dump if
|
||||
the table type is _NOT_ one of these types
|
||||
*/
|
||||
strmake(table_type, row[1], NAME_LEN-1);
|
||||
strmake(table_type, row[0], NAME_LEN-1);
|
||||
if (opt_delayed)
|
||||
{
|
||||
if (strcmp(table_type,"MyISAM") &&
|
||||
|
|
Loading…
Reference in a new issue