Skip to content

Commit 87271a4

Browse files
committed
Bug#37334107: Optimize performance of mysql query result output
Profiling client running a query with a large number of result rows shows some code parts that could be optimized. In particular, the query that returns fields encoded as hex strings shows some optimization targets. Solution improvement is small (1-2% in particular test), but could be helpful anyway with really large result sets. Change-Id: I7197bf075ab0f92a597c5325ccb0e1c2dc1e88bb
1 parent b2dec06 commit 87271a4

File tree

1 file changed

+47
-27
lines changed

1 file changed

+47
-27
lines changed

client/mysql.cc

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
6565
#include "strmake.h"
6666
#include "strxmov.h"
6767
#include "strxnmov.h"
68+
#include "template_utils.h"
6869
#include "typelib.h"
6970
#include "violite.h"
7071

@@ -3941,14 +3942,28 @@ static bool is_binary_field(MYSQL_FIELD *field) {
39413942

39423943
static void print_as_hex(FILE *output_file, const char *str, ulong len,
39433944
ulong total_bytes_to_send) {
3944-
const char *ptr = str, *end = ptr + len;
3945+
const unsigned char *ptr = pointer_cast<const unsigned char *>(str);
3946+
const unsigned char *end = ptr + len;
39453947
ulong i;
39463948

39473949
if (str != nullptr) {
39483950
fprintf(output_file, "0x");
3949-
for (; ptr < end; ptr++)
3950-
fprintf(output_file, "%02X",
3951-
*(static_cast<const uchar *>(static_cast<const void *>(ptr))));
3951+
ulong remaining = len;
3952+
static const unsigned char hex_digits[] = "0123456789ABCDEF";
3953+
unsigned char chunk_buf[64];
3954+
while (ptr < end) {
3955+
// write up to 32 input bytes at a time for performance
3956+
// (up to 64 bytes of hex output)
3957+
const size_t chunk_input_size = std::min((uint)remaining, 32U);
3958+
for (size_t j = 0; j < chunk_input_size; j++) {
3959+
const size_t offset = 2 * j;
3960+
chunk_buf[offset] = hex_digits[(*ptr >> 4) & 0x0F];
3961+
chunk_buf[offset + 1] = hex_digits[(*ptr) & 0x0F];
3962+
ptr++;
3963+
}
3964+
fwrite(chunk_buf, 1, 2 * chunk_input_size, output_file);
3965+
remaining -= chunk_input_size;
3966+
}
39523967
/* Printed string length: two chars "0x" + two chars for each byte. */
39533968
i = 2 + len * 2;
39543969
} else {
@@ -4005,11 +4020,13 @@ static void print_table_data(MYSQL_RES *result) {
40054020
tee_puts(separator.ptr(), PAGER);
40064021
}
40074022

4023+
const uint num_fields = mysql_num_fields(result);
4024+
40084025
while ((cur = mysql_fetch_row(result))) {
40094026
ulong *lengths = mysql_fetch_lengths(result);
40104027
(void)tee_fputs("| ", PAGER);
40114028
mysql_field_seek(result, 0);
4012-
for (uint off = 0; off < mysql_num_fields(result); off++) {
4029+
for (uint off = 0; off < num_fields; off++) {
40134030
const char *buffer;
40144031
uint data_length;
40154032
uint field_max_length;
@@ -4029,31 +4046,33 @@ static void print_table_data(MYSQL_RES *result) {
40294046
field = mysql_fetch_field(result);
40304047
field_max_length = field->max_length;
40314048

4032-
/*
4033-
How many text cells on the screen will this string span? If it
4034-
contains multibyte characters, then the number of characters we occupy
4035-
on screen will be fewer than the number of bytes we occupy in memory.
4036-
4037-
We need to find how much screen real-estate we will occupy to know how
4038-
many extra padding-characters we should send with the printing
4039-
function.
4040-
*/
4041-
visible_length = charset_info->cset->numcells(charset_info, buffer,
4042-
buffer + data_length);
4043-
extra_padding = (uint)(data_length - visible_length);
4044-
40454049
if (opt_binhex && is_binary_field(field))
40464050
print_as_hex(PAGER, cur[off], lengths[off], field_max_length);
4047-
else if (field_max_length > MAX_COLUMN_LENGTH)
4048-
tee_print_sized_data(buffer, data_length,
4049-
MAX_COLUMN_LENGTH + extra_padding, false);
40504051
else {
4051-
if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
4052-
tee_print_sized_data(buffer, data_length,
4053-
field_max_length + extra_padding, true);
4054-
else
4052+
/*
4053+
How many text cells on the screen will this string span? If it
4054+
contains multibyte characters, then the number of characters we occupy
4055+
on screen will be fewer than the number of bytes we occupy in memory.
4056+
4057+
We need to find how much screen real-estate we will occupy to know how
4058+
many extra padding-characters we should send with the printing
4059+
function.
4060+
*/
4061+
visible_length = charset_info->cset->numcells(charset_info, buffer,
4062+
buffer + data_length);
4063+
extra_padding = (uint)(data_length - visible_length);
4064+
4065+
if (field_max_length > MAX_COLUMN_LENGTH)
40554066
tee_print_sized_data(buffer, data_length,
4056-
field_max_length + extra_padding, false);
4067+
MAX_COLUMN_LENGTH + extra_padding, false);
4068+
else {
4069+
if (num_flag[off] != 0) /* if it is numeric, we right-justify it */
4070+
tee_print_sized_data(buffer, data_length,
4071+
field_max_length + extra_padding, true);
4072+
else
4073+
tee_print_sized_data(buffer, data_length,
4074+
field_max_length + extra_padding, false);
4075+
}
40574076
}
40584077
tee_fputs(" |", PAGER);
40594078
}
@@ -5519,13 +5538,14 @@ void tee_write(FILE *file, const char *s, size_t slen, int flags) {
55195538
#ifdef _WIN32
55205539
const bool is_console = my_win_is_console_cached(file);
55215540
#endif
5541+
const bool is_mb = use_mb(charset_info);
55225542
const char *se;
55235543
for (se = s + slen; s < se; s++) {
55245544
const char *t;
55255545

55265546
if (flags & MY_PRINT_MB) {
55275547
int mblen;
5528-
if (use_mb(charset_info) && (mblen = my_ismbchar(charset_info, s, se))) {
5548+
if (is_mb && (mblen = my_ismbchar(charset_info, s, se))) {
55295549
#ifdef _WIN32
55305550
if (is_console)
55315551
my_win_console_write(charset_info, s, mblen);

0 commit comments

Comments
 (0)