MDEV-8696: Adding indexes on empty table is slow with large innodb_sort_buffer_size.

Analysis: Current implementation will write and read at least one block
(sort_buffer_size bytes) from disk / index even if that block does not
contain any records.

Fix: Avoid writing / reading empty blocks to temporary files (disk).
This commit is contained in:
Jan Lindström 2015-10-27 13:00:15 +02:00
commit 13884cf206
19 changed files with 297 additions and 42 deletions

View file

@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2005, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -871,6 +872,8 @@ row_merge_read(
success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf,
ofs, srv_sort_buf_size);
srv_stats.merge_buffers_read.inc();
#ifdef POSIX_FADV_DONTNEED
/* Each block is read exactly once. Free up the file cache. */
posix_fadvise(fd, ofs, srv_sort_buf_size, POSIX_FADV_DONTNEED);
@ -905,6 +908,7 @@ row_merge_write(
DBUG_EXECUTE_IF("row_merge_write_failure", return(FALSE););
ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, ofs, buf_len);
srv_stats.merge_buffers_written.inc();
#ifdef UNIV_DEBUG
if (row_merge_print_block_write) {
@ -1736,7 +1740,7 @@ write_buffers:
/* We have enough data tuples to form a block.
Sort them and write to disk. */
if (buf->n_tuples) {
if (UNIV_LIKELY(buf->n_tuples)) {
if (dict_index_is_unique(buf->index)) {
row_merge_dup_t dup = {
buf->index, table, col_map, 0};
@ -1777,13 +1781,17 @@ write_buffers:
dict_index_get_lock(buf->index));
}
row_merge_buf_write(buf, file, block);
/* Do not write empty buffers to temporary file */
if (buf->n_tuples) {
if (!row_merge_write(file->fd, file->offset++,
block)) {
err = DB_TEMP_FILE_WRITE_FAILURE;
trx->error_key_num = i;
break;
row_merge_buf_write(buf, file, block);
if (!row_merge_write(file->fd, file->offset++,
block)) {
err = DB_TEMP_FILE_WRITE_FAILURE;
trx->error_key_num = i;
break;
}
}
UNIV_MEM_INVALID(&block[0], srv_sort_buf_size);
@ -2068,6 +2076,9 @@ done1:
mem_heap_free(heap);
b2 = row_merge_write_eof(&block[2 * srv_sort_buf_size],
b2, of->fd, &of->offset);
srv_stats.merge_buffers_merged.inc();
return(b2 ? DB_SUCCESS : DB_CORRUPTION);
}
@ -3747,17 +3758,21 @@ wait_again:
DEBUG_FTS_SORT_PRINT("FTS_SORT: Complete Insert\n");
#endif
} else {
row_merge_dup_t dup = {
sort_idx, table, col_map, 0};
/* Sorting and inserting is required only if
there really is records */
if (UNIV_LIKELY(merge_files[i].n_rec)) {
row_merge_dup_t dup = {
sort_idx, table, col_map, 0};
error = row_merge_sort(
trx, &dup, &merge_files[i],
block, &tmpfd);
error = row_merge_sort(
trx, &dup, &merge_files[i],
block, &tmpfd);
if (error == DB_SUCCESS) {
error = row_merge_insert_index_tuples(
trx->id, sort_idx, old_table,
merge_files[i].fd, block);
if (error == DB_SUCCESS) {
error = row_merge_insert_index_tuples(
trx->id, sort_idx, old_table,
merge_files[i].fd, block);
}
}
}