Warm up for database cache
Updated at by ospiFor a better mysql client experience a properly buffed up server might turn a total I/O slur into nothing happened. Here's a couple of ways to warm up your database caches on MariaDB / MySQL server before throwing it to the wolves.
Warmup with SELECT
s from general_log
Let's say you're bringing online another binlog slave and you can grab general_log from an already busy slave. The log format is pretty horrible, so it needs some tr|sed|grep-magic. A more proficient cli-toolist can probably achieve the same output with one command but I need a few more pipes :)
Snippet of the general log might look like this
150917 11:42:21 83 Quit
150917 11:43:39 84 Connect admin@localhost as anonymous on woofwoof
84 Query SELECT * FROM muchdata WHERE content LIKE '%derp'
150917 11:43:51 85 Connect admin@localhost as anonymous on woofwoof
85 Query SELECT * FROM bigtable WHERE
content LIKE '%derp'
87 Query SELECT * FROM bigtable WHERE id = 1
AND content LIKE '%meh%'
ORDER BY content DESC
87 Quit
After ^beginning of the line there's an optional timestamp, might be some \t
abs and \s
paces, a running thread [0-9]
number, \s
pace, command and input for the command spanning over multiple lines. I ended up with a monster like this :
sed -E 's/^(\t|[0-9]{6}\s[0-9:]{8})\s+([0-9]+)/~~\2/g'|tr '\n' ' '|tr '\t' ' '|grep -oP '~~[0-9]+\s+Query\s+\KSELECT.*?(?=~~[0-9]+)'|sed 's/ $/;/g'
This will normalize the line beginnings to two tildes and a thread number, replace tabs and newlines with space, grep the SELECT between two ~~[thread-number] patterns and slap a semicolon before eol. One assumption is that in multiline queries, new query lines won't start with \s
pace(s) and a number(s), so it might need a bit more work on your logs. Anyway the output on the log snippet above is:
SELECT * FROM muchdata WHERE content LIKE '%derp';
SELECT * FROM bigtable WHERE content LIKE '%derp';
SELECT * FROM bigtable WHERE id = 1 AND content LIKE '%meh%' ORDER BY content DESC;
Warmup with SELECT count(*)
and SHOW INDEX
Using information from SHOW INDEX
and executing SELECT count(*)
on the tables. Plus a little awful awk calculus to limit queries to top ~30% of IDs after reaching parameter max_rows
. A short script :
#!/bin/bash
database="woofwoof"
mysql_options="-uadminuser -pderp"
max_rows=100000
mysql $mysql_options $database -Bn -e "SHOW TABLES" 2>/dev/null|sed '1,1d'|xargs -I{} mysql $mysql_options $database -Bn -e "SHOW INDEX FROM $database.\`{}\` WHERE Key_name='PRIMARY'" 2>/dev/null|grep -v '^Table.*'|awk -v max_rows=$max_rows '{limit=($7<max_rows)?$7:int(max_rows+($7-max_rows)/5); print "SELECT count(*) FROM `" $1 "` ORDER BY `" $5 "` DESC LIMIT " limit ";" }'
Spills out:
SELECT count(*) FROM `another_table` ORDER BY `id` DESC LIMIT 7;
SELECT count(*) FROM `bigtable` ORDER BY `id` DESC LIMIT 204482;
another_table
is fully buffered with cardinality of 7. bigtable
has cardinality of ~600k, so the awk
is limiting.
Warmup with innodb_buffer_pool_load_at_startup
A server already hard at work can dump it's innodb_buffer_pool
to disk on exit and load the dump on startup. Depending on how much your active buffer pool changes over time and for how long the server is out, this might work or be a total waste of I/O. Enable dump by adding the following variables to my.cnf
(and SET GLOBAL
as they're dynamic).
innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1
innodb_buffer_dump_pct=25
innodb_buffer_dump_pct
is the percentage 0-100 of most-recently-used-pages. 100 meaning the whole buffer pool is dumped and 0 is just being weird.