diff options
author | Vladislav Vaintroub <wlad@montyprogram.com> | 2012-06-08 19:15:01 +0200 |
---|---|---|
committer | Vladislav Vaintroub <wlad@montyprogram.com> | 2012-06-08 19:15:01 +0200 |
commit | afe1ef5e3a1824ebbfd31fa95b6a198045a0ed34 (patch) | |
tree | b19230ae13ba02808b619513a00333a8c67903c3 /sql-common | |
parent | e326a3893f1386875e82b0233b30434a4d296af5 (diff) | |
download | mariadb-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.c | 97 |
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); } |