2016-12-01 2 views
0

Я ищу создать функцию Postgres, который кэширует результаты длительных запросов, так что нужно только быть выполнена один раз за одну транзакцию:индекс Результаты Postgres таблицы Функция

CREATE OR REPLACE FUNCTION get_records (
    _state VARCHAR(10) 
) 
RETURNS TABLE (
    id UUID 
) AS 
$$ 
DECLARE 
    _temptable VARCHAR; 
BEGIN 
    _temptable := FORMAT('temp_state_%s', _state); 

    IF NOT EXISTS(SELECT 1 FROM pg_tables WHERE tablename = _temptable) THEN 
    EXECUTE FORMAT('CREATE TEMPORARY TABLE %I (id UUID NOT NULL, PRIMARY KEY(_uid)) ON COMMIT DROP', _temptable); 
    EXECUTE FORMAT('INSERT INTO %I SELECT id FROM very_complex_nested_query', _temptable); 
    EXECUTE FORMAT('ANALYZE %I', _temptable); 
    END IF; 

    RETURN QUERY EXECUTE FORMAT('SELECT id FROM %I', _temptable); 
END; 
$$ 
LANGUAGE 'plpgsql'; 

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

SELECT mt.* 
FROM my_table1 mt 
    INNER JOIN get_records('new') nr ON mt.id = nr.id 
SELECT mt.* 
FROM my_table2 mt 
    INNER JOIN get_records('new') nr ON mt.id = nr.id 
SELECT mt.* 
FROM my_table3 mt 
    INNER JOIN get_records('new') nr ON mt.id = nr.id 
-- ... many more 

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

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

Как я могу вернуть «таблицу» из функции Postgres, а не только результаты запроса?

  1. Я использую функцию, чтобы построить временную таблицу вместо материализованные представления, чтобы получить вокруг «where clause doesn't get pushed into view that contains aggregation» вопрос.
  2. Я мог бы создать временную таблицу, а затем обратиться к ней непосредственно во всех запросах, но это означало бы, что нужно создать какой-то механизм блокировки, чтобы гарантировать, что запросы не выполняются слишком рано, а инструмент, использование не очень хорошо поддерживает такие механизмы.
+1

Не создавайте временную таблицу, не используйте временную таблицу. Не анализируйте таблицу temp. Поместите «very_complex_nested_query» в обычную функцию 'sql'. Запрос, использующий эту функцию sql, может быть оптимизирован намного лучше, чем черный ящик, который PL/pgSQL представляет оптимизатору. –

+0

@a_horse_with_no_name Но ... «very_complex_nested_query» занимает 5 минут, и, поскольку я присоединяюсь к результатам к сотням отдельных запросов, я добавляю дни к общему времени выполнения. Разве это не точный пример временного стола? Что вы подразумеваете под «простой функцией sql»? –

+0

Я имею в виду 'language sq' вместо' language plpgsql', но если вы хотите его индексировать, вам нужно создать индекс в таблице temp. –

ответ

0

Вы можете попробовать модификатор STABLE, который указывает, что

СТАБИЛЬНЫЙ указывает, что функция не может изменять базу данных, и что в пределах одной таблицы сканирования она постоянно будет возвращать один и тот же результат для одних и тех же значений аргумента , но его результат может измениться в SQL-операторах.

новее версии для версии Postgres поддерживают материализованные виды. Вы можете создать материализованное представление для соединения. Представленные AFAIK представления также поддерживают индексы.

+0

Возвращая таблицу, которая используется в предложении FROM, не будет ли она проверяться только один раз в любом случае?В любом случае ни STABLE, ни IMMUTABLE, похоже, не отображают базовый индекс таблицы temp. Что касается материализованных представлений, проблема в том, что вы не можете воспользоваться ограничениями проверки (например, в секционированной таблице), если вы выполняете агрегацию, что приводит к сканированию всех разделов (и мой 5-минутный запрос становится 18 -вой запрос) - это было для меня неожиданностью, когда я увидел план из десяти тысяч строк! –