MySQL запросы быстры, когда выполняются напрямую, но очень медленно, когда запускаются как хранимые процедуры. - PullRequest
10 голосов
/ 24 октября 2011

Я пытался выяснить, что не так с набором запросов, которые у меня есть, и я просто запутался в этом моменте.

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

Есть только одна «крошечная» проблема, это сначала простая UPDATE, затем INSERT с использованием SELECT с подвыбором и, наконец, еще одна UPDATE. Выполняя эти запросы вручную, я получаю общее время выполнения 0,057 с, не слишком потертое.

Теперь я пытаюсь создать хранимую процедуру с этими запросами и пятью входными переменными, я запускаю эту процедуру, и с первой попытки это заняло 47.096 с, а последующие обращения к ней показали аналогичное время выполнения (от 35 до 50 с). Выполнение отдельных запросов из MySQL Workbench по-прежнему показывает время выполнения менее 0,1 с

На самом деле в этих запросах нет ничего необычного, так почему же хранимая процедура занимает вечность, а запросы сами по себе занимают лишь доли секунды? Есть ли какая-то особенность MySQL, которую я здесь упускаю?

Дополнительные результаты тестирования:

Кажется, что если я запускаю запросы в MySQL Workbench, но использую переменные, а не просто помещаю значения переменных в запросы, он выполняется так же медленно, как и хранимая процедура. Поэтому я попытался изменить хранимую процедуру, чтобы использовать статические значения вместо переменных, и внезапно она запустилась невероятно быстро. Очевидно, по какой-то причине использование переменной делает ее чрезвычайно медленной (например, первый запрос UPDATE идет от примерно 0,98 с тремя переменными до 0,04-0,05, когда я использую значения переменных непосредственно в запросе, независимо от того, если он находится в хранимой процедуре или выполняет запрос напрямую).

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

Ответы [ 5 ]

9 голосов
/ 11 февраля 2014

У меня была такая же проблема. Проведя некоторое время, я обнаружил, что проблема заключалась в сопоставлении, когда MySQL сравнивал текст.

TL; DR: таблица была создана в одном сопоставлении, в то время как MySQL «думал», что переменная находится в другом сопоставлении. Поэтому MySQL не может использовать индекс, предназначенный для запроса.

В моем случае таблица была создана с сопоставлением ( latin1 , latin1_swedish_ci ). Чтобы заставить MySQL использовать индекс, мне пришлось изменить предложение where в хранимой процедуре с

    UPDATE ... WHERE mycolumn = myvariable

до

    UPDATE ... WHERE mycolumn = 
        convert(myvariable using latin1) collate latin1_swedish_ci

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

    CREATE PROCEDURE foo.'bar'()
    BEGIN
        UPDATE mytable SET mycolumn1 = variable1
        WHERE mycolumn2 = 
            convert(variable2 using latin1) collate latin1_swedish_ci
    END;

где ( latin1 , latin1_swedish_ci ) - это то же самое сопоставление, с которым была создана моя таблицаA .

Чтобы проверить, использует ли MySQL индекс или нет, вы можете изменить хранимую процедуру для запуска оператора explain следующим образом:

    CREATE PROCEDURE foo.'bar'()
    BEGIN
        EXPLAIN SELECT * FROM table WHERE mycolumn2 = variable2
    END;

В моем случае результат explain показал, что при выполнении запроса индекс не использовался.

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

Дополнительную информацию о проблеме сопоставления можно найти здесь: http://lowleveldesign.wordpress.com/2013/07/19/diagnosing-collation-issue-mysql-stored-procedure/ Резервная ссылка: http://www.codeproject.com/Articles/623272/Diagnosing-a-collation-issue-in-a-MySQL-stored-pro

4 голосов
/ 29 апреля 2013

У меня была похожая проблема. Выполнение MySQL было ужасно медленным. Но коллега помог мне. Проблема заключалась в том, что AUTOCOMMIT был правдой; Таким образом, каждая вставка и выборка создавали полную транзакцию. Затем я запускаю свою процедуру с

SET autocommit=0; 

в начале и

SET autocommit=1;                    

в конце. Производительность возросла с почти 500 до 4 с

0 голосов
/ 17 апреля 2015

Сегодня мы сталкиваемся с тем, что процедуры замедляются, даже если они выполняются очень быстро, как прямые запросы, и имеют имена параметров (или, предположительно, переменных), которые совпадают с именами столбцов. Краткая версия: не используйте имя параметра, совпадающее с одним из столбцов в запросе, в котором оно будет использоваться. Например, если у вас есть поле с именем account_id и параметр с таким же именем, измените его на что-то вроде in_account_id, и время выполнения может увеличиться с нескольких секунд до сотых долей секунды.

0 голосов
/ 25 октября 2011

Поскольку я не хотел тратить слишком много времени, пытаясь выяснить, почему использование переменных в моих хранимых процедурах делает их чрезвычайно медленными, я решил применить исправление, которое некоторые люди посчитали бы довольно уродливым. Я просто выполнял каждый запрос непосредственно из уровня доступа к данным моего приложения. Не самый красивый способ сделать это (поскольку многие другие вещи для этого приложения используют хранимые процедуры), но он работает, и теперь пользователю не придется ждать более 40 секунд для определенных действий, поскольку они происходят почти мгновенно.

Итак, на самом деле не решение или объяснение того, что происходило, но, по крайней мере, это работает.

0 голосов
/ 24 октября 2011

Upvote за очень интересный и важный вопрос. Я нашел это обсуждение некоторых причин, по которым хранимая процедура может быть медленной. Мне было бы интересно увидеть реакцию читателей на это.

Основная рекомендация, которую я взял из обмена: это помогает добавить больше индексов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...