Как предварительно загрузить таблицы в буферный пул INNODB с MySQL?
У меня есть приложение электронной коммерции, которое использует MySQL, и я бы хотел, чтобы оно было быстрее. При обращении к части # на веб-сайте, к которому ранее обращались, эта часть быстро загружается, поскольку все необходимые данные уже находятся в пуле буферов INNODB. Однако, если part # никогда не загружался ранее, эти данные еще не находятся в пуле буферов, поэтому их нужно читать с диска, и это медленно. Я установил буферный пул INNODB на 2 ГБ, а вся эта база данных - всего около 350 МБ, поэтому есть достаточно места для загрузки всей базы данных в буферный пул. Из статистики INNODB я вижу, что сейчас используется только около половины пула буферов.
Я нашел ссылки на предварительную загрузку данных, также известную как "прогрев" пула буферов, такой как быстрая предварительная загрузка таблиц Innodb в пул буферов или mysqldump.azundris.com/archives/70-Innodb-cache-preloading- используя-blackhole.html. Стратегия в основном предусматривает принудительное сканирование таблицы для каждой таблицы, поскольку MySQL не имеет встроенного способа предварительной загрузки данных.
Я не хочу вручную создавать скрипт, который перечисляет каждую таблицу в моей базе данных и должен это делать. Как я могу создать сценарий, который проходит и выполняет выбор для каждой таблицы автоматически и автоматически выбирает неиндексированный столбец, чтобы выполнить сканирование таблицы?
3 ответа
Это должно дать вам список запросов для запуска;)
SELECT
CONCAT('SELECT ',MIN(c.COLUMN_NAME),' FROM ',c.TABLE_NAME,' WHERE ',MIN(c.COLUMN_NAME),' IS NOT NULL')
FROM
information_schema.COLUMNS AS c
LEFT JOIN (
SELECT DISTINCT
TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME
FROM
information_schema.KEY_COLUMN_USAGE
) AS k
USING
(TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME)
WHERE
c.TABLE_SCHEMA = 'yourDatabase'
AND k.COLUMN_NAME IS NULL
GROUP BY
c.TABLE_NAME
Вы можете поместить его в хранимую процедуру и просмотреть курсор с помощью курсора. Создайте подготовленный оператор из каждой строки и выполните.
Этот запрос вернет имена таблиц в вашей базе данных, поэтому вам не нужно вводить их вручную:
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'database name'
Затем для каждого имени таблицы форсируют сканирование таблицы.
Вот хранимая процедура, которая выполняется в цикле и загружает указанные таблицы в пул буферов. Вы можете вставить все свои таблицы с помощью инструкции INSERT...SELECT, которая считывает таблицу INFORMATION_SCHEMA.TABLES и вставляет ее в pin_buffer_pool_config.
CREATE DATABASE IF NOT EXISTS `swanhart`;
use swanhart;
CREATE TABLE IF NOT EXISTS `pin_buffer_pool_config` (
`schema_name` varchar(50) DEFAULT NULL,
`table_name` varchar(50) DEFAULT NULL,
`index_name` varchar(255) DEFAULT 'PRIMARY' comment 'null for all indexes',
`where_clause` varchar(255) DEFAULT NULL comment 'do not include the WHERE keyword'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
delimiter ;;
DROP PROCEDURE IF EXISTS pin_buffer_pool;
-- load all the columns for the given index
-- into the buffer pool
CREATE PROCEDURE pin_buffer_pool()
BEGIN
DECLARE v_done boolean default false;
DECLARE v_stmt TEXT default null;
DECLARE v_got_lock tinyint default 0;
DECLARE v_cursor CURSOR FOR
SELECT CONCAT('SELECT COUNT(CONCAT(',
GROUP_CONCAT(column_name ORDER BY seq_in_index), ')) INTO @discard
FROM `', s.table_schema, '`.`', s.table_name,
'` FORCE INDEX(`', s.index_name, '`)',
IF(where_clause IS NOT NULL, CONCAT(' WHERE ', where_clause), '')
) AS stmt
FROM information_schema.statistics s
JOIN percona.pin_buffer_pool_config pbpc
ON pbpc.table_name = s.table_name
AND pbpc.schema_name = s.table_schema
-- when the index_name is null, it means warm all indexes for the table
AND s.index_name = ifnull(pbpc.index_name, s.index_name)
GROUP BY s.index_name;
DECLARE CONTINUE HANDLER FOR
SQLSTATE '02000'
SET v_done = TRUE;
-- DON'T HOLD A LONG TRANSACTION, START A NEW SNAPSHOT FOR EACH READ
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- abort if the last pin is still running
SELECT GET_LOCK('BUFFER_POOL_PIN', 0) INTO v_got_lock;
IF v_got_lock = 1 THEN
OPEN v_cursor;
cursorLoop: LOOP
FETCH v_cursor INTO v_stmt;
IF v_done THEN
CLOSE v_cursor;
LEAVE cursorLoop;
END IF;
set @v_stmt = v_stmt;
prepare v_bp_pin from @v_stmt;
execute v_bp_pin;
deallocate prepare v_bp_pin;
END LOOP;
SELECT RELEASE_LOCK('BUFFER_POOL_PIN') INTO @discard;
END IF;
END;;
DROP PROCEDURE IF EXISTS pin_buffer_pool_loop;;
CREATE PROCEDURE pin_buffer_pool_loop()
BEGIN
-- This procedure can be scheduled to start
-- every second with no harm done. It will
-- simply exit if more than one copy tries
-- to run. This means that an event can
-- be used to ensure the warming function is
-- always on and that it is looping faster
-- than innodb_old_blocks_time (default 1000 in 5.6)
SELECT GET_LOCK('BUFFER_POOL_PIN_LOOP_LOCK', 0) INTO @got_lock;
IF @got_lock = 1 THEN
LOOP
CALL pin_buffer_pool();
select sleep(.25) into @discard;
END LOOP;
SELECT RELEASE_LOCK('BUFFER_POOL_PIN_LOOP_LOCK') INTO @discard;
END IF;
END;;
delimiter ;