SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 05.08.2014 14:55:17

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Производительность в хранимых функциях

Добрый день. Есть хранимая функция, она максимально оптимизирована для производительности, больше не выжать. Поэтому так и записана

DELIMITER $$

CREATE DEFINER=`root`@`127.0.0.1` FUNCTION `SORT_STR`(`string1` VARCHAR(255)) RETURNS varchar(255) CHARSET utf8
    READS SQL DATA
    DETERMINISTIC
BEGIN
DECLARE sort VARCHAR(255);
DECLARE str1 VARCHAR(255);
DECLARE word VARCHAR(255);
CREATE TEMPORARY TABLE IF NOT EXISTS sort_t
(w VARCHAR(255));

SET str1 = LOWER(string1);
    sub_str_loop: LOOP
        SET word = SUBSTRING_INDEX(str1,' ', 1);
        SET str1 = trim(replace(str1, word, ''));
        INSERT INTO sort_t set w = word;
        IF str1 = '' THEN
            LEAVE sub_str_loop;
        END IF;
    END LOOP sub_str_loop;
    select group_concat(`w` ORDER BY `w` asc SEPARATOR  ' ') as words into sort from sort_t;
delete from  sort_t;
RETURN sort;
END

Делает она лишь 1, берет на входе строку -> разбивает ее на слова -> добавляет в временную таблицу -> сортирует -> отдает отсортированную строку.

Есть таблица InnoDB - количество записей 350 тысяч.
Есть колонка - Данные в ней примерно такие [Блок питания Chieftec A-135 APS-750C]

Update всей таблицы статичным значением, например нулл

UPDATE таблица SET колонка = null   
386398 row(s) affected
Rows matched: 386398  Changed: 386398  Warnings: 0   
17.659 sec



И тут начинается магия. Непонятное увеличение времени выполнения.

Небольшой бенчмарк (количество обновляемых строк - время) Запросы идут друг за другом со смешением по ИД записи что бы их не было до этого в кеше

1 - 0.031
10 - 0.063
100 - 0.187
1000 - 3.775
10000 - 246.310



Получается я быстрее сделаю 10 запросов в хранимой процедуре по 100 строк чем 1 на 1000 строк.
Что нужно Mysql для таких запросов ? Памяти хватает, сервер мощный. Где он буксует ?
Видно что в хранимой функции, но как ее оптимизировать ? почему меньшее кол-во строк выполняется в сумме быстрее чем большее ?

Отредактированно Technics (05.08.2014 14:57:05)

Неактивен

 

#2 05.08.2014 23:35:18

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Производительность в хранимых функциях

Какую именно команду выполняли для бенчмарка? Приведите пример.

Неактивен

 

#3 06.08.2014 00:58:48

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

rgbeast написал:

Какую именно команду выполняли для бенчмарка? Приведите пример.

Обычный запрос со смещением. Такие же данные можно получить ничего не смещая


UPDATE table SET поле1 = SORT_STR(поле2) WHERE id > x AND id < y
 

Делал так что бы значения брались всегда свежие которые не лежат в кеше, следовало бы ожидать при обновлении с первой записи увеличение производительности, но запрос


UPDATE table SET поле1 = SORT_STR(поле2) WHERE id < x
 

Ничем не отличался от запроса выше.
Индекс ПК

Неактивен

 

#4 06.08.2014 01:02:08

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Производительность в хранимых функциях

Получается, что один запрос на 1000 записей медленнее, чем 10 запросов по 100?
Тип таблиц InnoDB? Может быть дополнительный оверхед связан с транзакционностью.

1) попробуйте создавать временную таблицу:
CREATE TEMPORARY TABLE IF NOT EXISTS sort_t (w VARCHAR(255)) ENGINE=MEMORY;

2) попробуйте выполнить профилирование запросов

Неактивен

 

#5 06.08.2014 18:15:36

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

rgbeast написал:

Получается, что один запрос на 1000 записей медленнее, чем 10 запросов по 100?
Тип таблиц InnoDB? Может быть дополнительный оверхед связан с транзакционностью.

1) попробуйте создавать временную таблицу:
CREATE TEMPORARY TABLE IF NOT EXISTS sort_t (w VARCHAR(255)) ENGINE=MEMORY;

2) попробуйте выполнить профилирование запросов

Вначале на пункт 2. 
Вот что показывает профайлинг, сравнительная характеристика 2 запросов
Запрос


set profiling=1;
set profiling_history_size=100;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id < ХХ;
show profiles;
 

изменение 1 значения
http://cdn.joxi.ru/uploads/prod/2014/08/06/ba0/181/d40f809671a99c88149c87efa8725ec7464c3c6a.jpg

изменение 10 000 значений
http://cdn.joxi.ru/uploads/prod/2014/08/06/86a/03a/5855da774c5d5f29f9cbe8f89e1a62dd5bd0d3f9.jpg

Как видно с течением времени увеличивается время на делит и селект груп конкат. Если на делит я бы мог высказаться то предположений по поводу груп конкат нет, оно происходит в таблице которая находится в памяти, то есть временной, и мне казалось что скорость чтения не должна в них меняться. Но тут не так.



Принудительное указание на расположение временной таблицы в памяти ничего не изменило

Отредактированно Technics (06.08.2014 18:25:54)

Неактивен

 

#6 06.08.2014 18:25:22

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Производительность в хранимых функциях

DELETE FROM sort_t;

замените на
TRUNCATE sort_t;

тогда она не будет занимать времени.
В таблицу попробуйте добавить индекс и сделать ее в памяти:
CREATE TEMPORARY TABLE IF NOT EXISTS sort_t (w VARCHAR(255), KEY(w)) ENGINE=MEMORY;


Из примера пока не видно проблем с масштабируемостью.

Неактивен

 

#7 06.08.2014 18:33:10

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

rgbeast написал:

DELETE FROM sort_t;

замените на
TRUNCATE sort_t;

тогда она не будет занимать времени.
В таблицу попробуйте добавить индекс и сделать ее в памяти:
CREATE TEMPORARY TABLE IF NOT EXISTS sort_t (w VARCHAR(255), KEY(w)) ENGINE=MEMORY;


Из примера пока не видно проблем с масштабируемостью.

В функциях нельзя использовать такую конструкцию

TRUNCATE sort_t;


For stored functions (but not stored procedures), the following additional statements or operations are disallowed:

Statements that perform explicit or implicit commit or rollback.


Индекс в таблице как и предполагалось ничего не изменил, так же принудительное указание хранить временную таблицу в памяти не играет роли.


Почему не видно проблемы ?

время увеличилось.
10000*0.012 = 120 секунд

Отредактированно Technics (06.08.2014 18:35:50)

Неактивен

 

#8 06.08.2014 18:48:53

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

Вот более интересная статистика по увеличившему время запросу
Первая картинка это при 10 тысячах, вторая при 10

select group_concat(`w` ORDER BY `w` asc SEPARATOR  ' ') as words into sort from sort_t

http://cdn.joxi.ru/uploads/prod/2014/08/06/257/fdf/f5d81e1615c8f1753308bff545bb7ff28e265744.jpg
http://cdn.joxi.ru/uploads/prod/2014/08/06/1d4/2b1/6714930844fc5e8a6cb9dfad3181512ed6fe6011.jpg

DELETE FROM sort_t

http://cdn.joxi.ru/uploads/prod/2014/08/06/184/ca7/8487a3e557eb861e57c778665a39ac83ac3d8ee9.jpg
http://cdn.joxi.ru/uploads/prod/2014/08/06/45d/bb7/ad0442181096a894a646cdceae326e9acbf18dd7.jpg

Отредактированно Technics (06.08.2014 18:51:30)

Неактивен

 

#9 06.08.2014 19:08:33

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Производительность в хранимых функциях

Да, действительно странная картина. А время выполнения каждый раз одинаковое или есть динамика от начала к концу выполнения?

Неактивен

 

#10 06.08.2014 19:38:30

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

rgbeast написал:

Да, действительно странная картина. А время выполнения каждый раз одинаковое или есть динамика от начала к концу выполнения?

Не могу посмотреть динамику, выводится всего 100 запросов по профайлингу.

Посмотрел переменные локальные, все таблицы действительно создаются в памяти

SHOW STATUS LIKE '%Created_tmp%'


Странная картина так же и вот тут? выполняю 10 запросов подряд

update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id < 1000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 1000 and id < 2000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 2000 and id < 3000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 3000 and id < 4000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 4000 and id < 5000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 5000 and id < 6000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 6000 and id < 7000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 7000 and id < 8000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 8000 and id < 9000;
update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where id > 9000 and id < 10000;
 

http://cdn.joxi.ru/uploads/prod/2014/08/06/c88/7a3/48e53ee4c9638ccf64105e6d726f386e30e6e5d2.jpg

Для сравнения запрос

update PC7_PRODUCT set TITLE_SORT = SORT_STR(TITLE) where  id < 10000;
 

http://cdn.joxi.ru/uploads/prod/2014/08/06/610/2e4/ce6a88b8648794a3a3c3b4d6eb675e641ec9b13b.jpg

Неактивен

 

#11 06.08.2014 20:30:50

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Производительность в хранимых функциях

Для чистоты эксперимента сделайте >=1000 (вместо >1000), чтобы все записи вошли в первый набор.

Очень странное поведение. Какая версия MySQL? Если повторяется на новых версиях и можно сделать набор, на котором воспроизводится, то можно попробовать написать на bugs.mysql.com.

Неактивен

 

#12 06.08.2014 21:12:23

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

В общем решил вопрос. Все было связано с версиями.
Типом таблиц по умолчанию в конфиге был InnoDB.То есть при создании временной таблицы

CREATE TEMPORARY TABLE IF NOT EXISTS sort_t (w VARCHAR(255));

ей присваивался этот тип.

А этот баг распространяется на InnoDB, видимо что-то внутри движка спрятано в том что при длительном обращении ко временной таблице повышается время на операцию.

Конечно если бы не тупил и включил нормально то что вы посоветовали - ENGINE=MEMORY догадался бы быстрее.

В конфиге поставил

SET default_storage_engine=MYISAM;
 

И временная таблица начала создаваться этого типа. Ключ ENGINE=MEMORY при этом не нужен. А вот если временная таблица создается в InnoDB то ваш ключ как раз помогает ее превратить в какой то другой формат. Мануал так и не сказал ничего о том что InnoDB Создается в какой то другой памяти. Хотя по статистике показывал что создается все таки временная таблица находящаяся в памяти.

Неактивен

 

#13 06.08.2014 21:16:50

Technics
Участник
Зарегистрирован: 05.08.2014
Сообщений: 9

Re: Производительность в хранимых функциях

Осталось только понять волшебство почему Innodb временная таблица при указании ключа превращается  в MyISAM

A TEMPORARY table can only be of type MEMORY, MyISAM, MERGE, or InnoDB.

Temporary tables are not supported for MySQL Cluster.

Значит мемори это еще один тип таблицы, а не указание того что она находится в память.

Отредактированно Technics (06.08.2014 21:18:57)

Неактивен

 

#14 06.08.2014 21:30:54

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Производительность в хранимых функциях

У InnoDB сложное хранилище данных. Скорее всего поведение связано с тем, что все операции выполняются в одной транзакции. То есть, если что-то пойдет не так, InnoDB должен быть готов отменить все операции. Вероятно, из-за этого очещенные временные данные не исчезают, а помечаются как удаленные.

Не обязательно делать по-умолчанию MyISAM. Вы можете сменить тип на MyISAM или MEMORY только для одной таблицы.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson