summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@montyprogram.com>2012-06-08 19:15:01 +0200
committerVladislav Vaintroub <wlad@montyprogram.com>2012-06-08 19:15:01 +0200
commitafe1ef5e3a1824ebbfd31fa95b6a198045a0ed34 (patch)
treeb19230ae13ba02808b619513a00333a8c67903c3 /sql-common
parente326a3893f1386875e82b0233b30434a4d296af5 (diff)
downloadmariadb-git-afe1ef5e3a1824ebbfd31fa95b6a198045a0ed34.tar.gz
LP1008334 : Speedup specific datetime queries that got slower with introduction of microseconds in 5.3
- Item::get_seconds() now skips decimal arithmetic, if decimals is 0. This significantly speeds up from_unixtime() if no fractional part is passed. - replace sprintfs used to format temporal values by hand-coded formatting Query1 (original query in the bug report) BENCHMARK(10000000,DATE_SUB(FROM_UNIXTIME(RAND() * 2147483648), INTERVAL (FLOOR(1 + RAND() * 365)) DAY)) Query2 (Variation of query1 that does not use fractional part in FROM_UNIXTIME parameter) BENCHMARK(10000000,DATE_SUB(FROM_UNIXTIME(FLOOR(RAND() * 2147483648)), INTERVAL (FLOOR(1 + RAND() * 365)) DAY)) Prior to the patch, the runtimes were (32 bit compilation/AMD machine) Query1: 41.53 sec Query2: 23.90 sec With the patch, the runtimes are Query1: 32.32 sec (speed up due to removing sprintf) Query2: 12.06 sec (speed up due to skipping decimal arithmetic)
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/my_time.c97
1 files changed, 80 insertions, 17 deletions
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index b009f8da7b9..5ad037ab6c9 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -1044,6 +1044,27 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type)
/*
+ Helper function for datetime formatting.
+ Format number as string, left-padded with 0.
+
+ The reason to use own formatting rather than sprintf() is performance - in a
+ datetime benchmark it helped to reduced the datetime formatting overhead
+ from ~30% down to ~4%.
+*/
+
+static char* fmt_number(uint val, char *out, uint digits)
+{
+ uint i;
+ for(i= 0; i < digits; i++)
+ {
+ out[digits-i-1]= '0' + val%10;
+ val/=10;
+ }
+ return out + digits;
+}
+
+
+/*
Functions to convert time/date/datetime value to a string,
using default format.
This functions don't check that given MYSQL_TIME structure members are
@@ -1056,42 +1077,84 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type)
int my_time_to_str(const MYSQL_TIME *l_time, char *to, uint digits)
{
- ulong day= (l_time->year || l_time->month) ? 0 : l_time->day;
+ uint day= (l_time->year || l_time->month) ? 0 : l_time->day;
+ uint hour= day * 24 + l_time->hour;
+ char*pos= to;
if (digits == AUTO_SEC_PART_DIGITS)
digits= l_time->second_part ? TIME_SECOND_PART_DIGITS : 0;
DBUG_ASSERT(digits <= TIME_SECOND_PART_DIGITS);
- return sprintf(to,
- digits ? "%s%02lu:%02u:%02u.%0*lu"
- : "%s%02lu:%02u:%02u",
- (l_time->neg ? "-" : ""),
- day * 24L + l_time->hour, l_time->minute, l_time->second,
- digits, (ulong)sec_part_shift(l_time->second_part, digits));
+ if(l_time->neg)
+ *pos++= '-';
+
+ if(hour > 99)
+ /* Need more than 2 digits for hours in string representation. */
+ pos= longlong10_to_str((longlong)hour, pos, 10);
+ else
+ pos= fmt_number(hour, pos, 2);
+
+ *pos++= ':';
+ pos= fmt_number(l_time->minute, pos, 2);
+ *pos++= ':';
+ pos= fmt_number(l_time->second, pos, 2);
+
+ if (digits)
+ {
+ *pos++= '.';
+ pos= fmt_number((uint)sec_part_shift(l_time->second_part, digits),
+ pos, digits);
+ }
+
+ *pos= 0;
+ return (int) (pos-to);
}
+
int my_date_to_str(const MYSQL_TIME *l_time, char *to)
{
- return my_sprintf(to, (to, "%04u-%02u-%02u",
- l_time->year,
- l_time->month,
- l_time->day));
+ char *pos=to;
+ pos= fmt_number(l_time->year, pos, 4);
+ *pos++='-';
+ pos= fmt_number(l_time->month, pos, 2);
+ *pos++='-';
+ pos= fmt_number(l_time->day, pos, 2);
+ *pos= 0;
+ return (int)(pos - to);
}
+
int my_datetime_to_str(const MYSQL_TIME *l_time, char *to, uint digits)
{
+ char *pos= to;
+
if (digits == AUTO_SEC_PART_DIGITS)
digits= l_time->second_part ? TIME_SECOND_PART_DIGITS : 0;
DBUG_ASSERT(digits <= TIME_SECOND_PART_DIGITS);
- return sprintf(to,
- digits ? "%04u-%02u-%02u %02u:%02u:%02u.%0*lu"
- : "%04u-%02u-%02u %02u:%02u:%02u",
- l_time->year, l_time->month, l_time->day,
- l_time->hour, l_time->minute, l_time->second,
- digits, (ulong)sec_part_shift(l_time->second_part, digits));
+ pos= fmt_number(l_time->year, pos, 4);
+ *pos++='-';
+ pos= fmt_number(l_time->month, pos, 2);
+ *pos++='-';
+ pos= fmt_number(l_time->day, pos, 2);
+ *pos++=' ';
+ pos= fmt_number(l_time->hour, pos, 2);
+ *pos++= ':';
+ pos= fmt_number(l_time->minute, pos, 2);
+ *pos++= ':';
+ pos= fmt_number(l_time->second, pos, 2);
+
+ if (digits)
+ {
+ *pos++='.';
+ pos= fmt_number((uint) sec_part_shift(l_time->second_part, digits), pos,
+ digits);
+ }
+
+ *pos= 0;
+ return (int)(pos - to);
}