PostgreSQL Функция не работает с предложением WHERE - PullRequest
0 голосов
/ 20 апреля 2020

Я пытаюсь создать функцию в Postgres, чтобы мои запросы выполнялись быстрее по сравнению с Django ORM. Но проблема, с которой я сталкиваюсь, заключается в том, что результаты приходят, когда в запросе нет условия WHERE.

Это функция и ее вызов, который возвращает 0 строк:

CREATE OR REPLACE FUNCTION public.standard_search(search_term text, similarity_to integer)
    RETURNS TABLE(obj_id integer, app_num integer, app_for text, similarity integer)
    LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
    similarity integer;
BEGIN
    RETURN QUERY
        SELECT mark.id, mark.app_num, mark.app_for::text, levenshtein($1, focusword.word) AS similarity
        FROM mark
        INNER JOIN focusword ON (mark.id = focusword.mark_id)
        WHERE similarity <= $2
        ORDER BY similarity, mark.app_for, mark.app_num;
END
$BODY$;

select * from public.standard_search('millennium', 4)

Это это функция и ее вызов, который дает мне результаты, но медленный, так как фильтрация выполняется в вызове функции:

CREATE OR REPLACE FUNCTION public.standard_search(search_term text, similarity_to integer)
    RETURNS TABLE(obj_id integer, app_num integer, app_for text, similarity integer)
    LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
    similarity integer;
BEGIN
    RETURN QUERY
        SELECT mark.id, mark.app_num, mark.app_for::text, levenshtein($1, focusword.word) AS similarity
        FROM mark
        INNER JOIN focusword ON (mark.id = focusword.trademark_id)
        ORDER BY similarity, trad.app_for, mark.app_num;
END
$BODY$;

select * from public.standard_search('millennium', 4) where similarity <= 4

Может ли кто-нибудь пролить свет на то, что здесь на самом деле идет не так? После этого я могу работать над улучшением производительности.

Мне не удалось выполнить это через VIEWS, так как требовался хотя бы один параметр, т. Е. search_term для передачи в функцию levenshtein().

Я также столкнулся с проблемой передачи tuple в качестве параметра в функцию, которая снова будет использоваться в предложении where, например: WHERE mark.class in (1,2,3,4,5)

Я делал это ранее через Raw SQL особенность Django ORM, но пытаюсь сделать это здесь из-за увеличения производительности.

1 Ответ

1 голос
/ 23 апреля 2020

Идентификатор similarity используется различными путями. Не все имеют смысл ...

CREATE OR REPLACE FUNCTION public.standard_search(search_term text, similarity_to integer)
  RETURNS TABLE(obj_id integer, app_num integer, app_for text, <b>similarity</b> integer)  -- ①
  LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
   <b>similarity</b> integer; -- ②
BEGIN
   RETURN QUERY
   SELECT mark.id, mark.app_num, mark.app_for::text, levenshtein($1, focusword.word) AS <b>similarity</b>  -- ③
   FROM mark
   INNER JOIN focusword ON (mark.id = focusword.mark_id)
   WHERE <b>similarity</b> <= $2  -- ④
   ORDER BY <b>similarity</b>, mark.app_for, mark.app_num; -- ⑤
END
$BODY$;

① ... как столбец в типе возвращаемого значения, определенного RETURNS TABLE - фактически параметром OUT.

② ... as переменная - перекрывающая видимость параметра OUT. Но почему?

③ ... как псевдоним столбца в списке SELECT.

④ ... в предложении WHERE, что не имеет смысла. Это не относится к ③ (как вы, кажется, предполагаете). Имена вывода не отображаются в предложении WHERE. Там вы можете ссылаться только на входные имена столбцов - или на переменные и параметры. Поскольку переменная (скрывающая параметр, но это не имеет значения) равна NULL, строки не возвращаются. Ever.

⑤ ... в ORDER BY, что разрешает псевдоним столбца, определенный в ③

Это безумие. Даже мне было трудно понять, где это видно, и у меня есть некоторый опыт работы с этим. Избегайте именования конфликтов, как это. Следуйте некоторому соглашению об именах и используйте разные имена для параметров, переменных, имен столбцов и псевдонимов!

Related:

Возможное решение

Это будет иметь больше смысла:

CREATE OR REPLACE FUNCTION public.standard_search(_search_term text, _similarity_to integer)
  RETURNS TABLE(obj_id integer, app_num integer, app_for text, similarity integer) AS
$func$
   SELECT m.id, m.app_num, m.app_for::text, levenshtein(_search_term, f.word) AS sim
   FROM   mark      m
   JOIN   focusword f ON m.id = f.mark_id
   WHERE  levenshtein($1, f.word) <= _similarity_to
   ORDER  BY sim, m.app_for, m.app_num;
$func$  LANGUAGE sql;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...