Как избежать тупика в функции mysql только с запросами выбора? - PullRequest
0 голосов
/ 19 февраля 2012

У меня есть две функции для создания имени виртуального пути из таблицы с именем tree_elements. Путь к функции (id, language) вызывается при любом обновлении таблицы. Время от времени обновление таблицы приводит к взаимоблокировкам с сообщением об ошибке (пример):

select path(621163,"de") 
Deadlock found when trying to get lock; try restarting transaction

Я не понимаю, почему происходит блокировка. Функции используют только выбор, без обновления, без вставки, без удаления. Как я могу избежать этого явления?

Есть мои функции:

mysql> show create function path\G
*************************** 1. row ***************************
            Function: path
            sql_mode:
     Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION `path`(id integer, language char(2)) RETURNS varchar(255) CHARSET utf8
    READS SQL DATA
    DETERMINISTIC
    COMMENT 'Converts a record id into an url string with path'
begin
        declare ret varchar(255);
        declare r varchar(255);
  declare element varchar(255);
        set ret = path_component(id,language);
        set id = (select id_parent from tree_elements t where t.id=id);
        while (id > 0) do
    set element = concat(path_component(id,language), '/');
    if (locate( element, ret )) then return concat( 'Infinite loop in path for id ', id ); end if;
                set ret = concat(path_component(id,language), '/', ret );
                set id = (select id_parent from tree_elements t where t.id=id);
        end while;
        return ret;
end
character_set_client: latin1
collation_connection: latin1_swedish_ci
  Database Collation: utf8_general_ci

mysql> show create function path_component\G
*************************** 1. row ***************************
            Function: path_component
            sql_mode:
     Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION `path_component`( id integer, language char(2)) RETURNS varchar(500) CHARSET utf8
    READS SQL DATA
    DETERMINISTIC
begin
   declare f varchar(255);
        set f = (select case language
                when 'en' then title_en
                when 'de' then title_de
                else title_en
                end
        from tree_elements t where t.id=id);
        if (isnull(f) or length(trim(f)) = 0) then
                set f = (select title_en from tree_elements t where t.id=id);
        end if;
        return url(f);
end
character_set_client: latin1
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci

1 Ответ

0 голосов
/ 19 февраля 2012

Вам не нужно вставлять или обновлять данные для блокировки таблицы (или страниц таблицы). Выбор данных может заблокировать таблицу (в соответствии с политикой блокировки по умолчанию движка RDBMS). Поэтому у нас есть специальные директивы, чтобы запретить ядру не устанавливать блокировку для таблицы при выборе данных. (В SQL Server это можно получить, поставив With Директива NoLock после имени талбе). Когда вы выбираете несколько строк в таблице, существует вероятность того, что несколько страниц таблицы заблокированы. Когда вы выполняете два разных запроса для одной и той же таблицы и запрос 1 блокирует страницу, которая нужна запросу 2, а запрос 2 блокирует страницу, которая нужна запросу 1, вы получаете тупик. Одно из решений - заставить запрос использовать определенный индекс, который будет Гарантируйте, что страницы будут заблокированы в определенном порядке. Обычно тупиковые ситуации - это самые сложные проблемы, с которыми нужно справиться.

...