Postgresql Медленно для пользовательской функции, php, но быстро, если напрямую вводить в psql с помощью текстового поиска с индексом джина - PullRequest
1 голос
/ 27 июля 2010

У меня есть 3 таблицы Person, Names и Notes.Каждый человек имеет несколько имен и имеет дополнительные примечания.У меня есть полнотекстовый поиск по некоторым столбцам имен и заметок (см. Ниже), они отлично работают, если слово, с которым я ищу, находится в наборе результатов или в БД, это для пользовательских функций, php и psql.Проблема теперь в том, что когда искомое слово отсутствует в БД, запрос становится очень медленным в php и пользовательской функции, но все еще быстрым в psql.На PSQL меньше 1 с, остальные более 10 с.

Таблицы:

Person | id, birthday  
Name   | person_id, name, fs_name  
Notes  | person_id, note, fs_note  

Рядом с индексами PK и FK, индексом джина для fs_name и fs_note.

Функция / запрос

create or replace function queryNameFunc (TEXT)
returns TABLE(id int, name TEXT) as $$

    select id, name
    from person_name pnr
    inner join person pr on (pnr.person_id=pr.id) 
    left join personal_notes psr on (psr.person_id = pr.id) 
    where pr.id in 
        (select distinct(id)
         from person_name pn
         inner join person p on (p.id = pn.person_id)
         left join personal_notes ps on (ps.person_id = p.id)
         where tname @@ to_tsquery($1)
         limit 20);

$$ language SQL;

Условие где здесь урезано, так что, например, если я делаю 'john & james' на $ 1, а данные на БД, тогда результаты быстрые, но если 'john and james'не в дб, то медленно.Это стало медленнее, так как у меня есть 1M записей на человека и 3M + на именах (все фиктивные записи).Есть идеи, как это исправить?Я попытался перезапустить сервер, перезапустить postgresql.

1 Ответ

3 голосов
/ 27 июля 2010

База данных должна предварительно подготовить внутренний запрос, прежде чем она узнает о параметре.Это может привести к неверному плану запросов.Чтобы избежать этой проблемы в функции, используйте язык plpgsql и используйте EXECUTE внутри функции:

CREATE OR REPLACE FUNCTION queryNameFunc (TEXT) RETURNS TABLE(id INT, name TEXT) AS $$
BEGIN
    RETURN QUERY EXECUTE '
        SELECT 
            id, 
            name 
        FROM 
            person_name pnr
                INNER JOIN person pr ON (pnr.person_id=pr.id)
                LEFT JOIN personal_notes psr ON (psr.person_id = pr.id)
               WHERE 
            pr.id IN(
                SELECT 
                    DISTINCT(id) 
                FROM 
                    person_name pn
                        INNER JOIN person p ON (p.id = pn.person_id)
                        LEFT JOIN personal_notes ps ON (ps.person_id = p.id)
                        WHERE tname @@ to_tsquery($1)
                        LIMIT 20)' USING $1;
END;
$$ LANGUAGE plpgsql;

Это работает в версии 8.4, и вам необходимо установить plpgsql:

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