Как создать хранимую функцию обновления строк в Postgres? - PullRequest
0 голосов
/ 10 июля 2011

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

У меня есть таблица, которая содержит следующие столбцы: число |last_update |growth_per_second

И мне нужно эффективное решение для обновления числа на основе last_update и коэффициента роста и установки значения last_update на текущее время.У меня, вероятно, будет 100, может быть, 150 тыс. Строк.Мне нужно обновить все строки одновременно, если это возможно, но если это займет слишком много времени, я могу разбить его на более мелкие части.

Ответы [ 2 ]

1 голос
/ 23 сентября 2012

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

Теперь, при условии, что ваши данные все вставлены и не обновлены, я бы не сохранил бы эту информацию непосредственно в вашей базе данных. Если это небольшой объем информации, вы все равно получите индексное сканирование, и если вы возвращаете небольшой набор результатов, вы сможете быстро его вычислить.

Вместо этого я бы сделал это: ваш столбец last_update должен быть внешним ключом той же таблицы. Предположим, ваш стол выглядит так:

CREATE TABLE hits (
    id bigserial primary key,
    number_hits bigint not null,
    last_update_id bigint references hits(id),
    ....
);

Тогда я бы создал следующие функции. Обратите внимание на предостережения ниже.

CREATE FUNCTION last_update(hits) RETURNS hits IMMUTABLE LANGUAGE SQL AS $$
    SELECT * FROM hits WHERE id = $1.last_update_id;
$$;

Эта функция позволяет при небольшом наборе результатов переходить к последней записи обновления. Обратите внимание, что неизменное обозначение здесь безопасно только в том случае, если вы гарантируете, что в таблице совпадений нет обновлений или удалений. Если вы сделаете это, то вы должны изменить его на стабильный, и вы потеряете способность индексировать вывод. Если вы даете эту гарантию, а затем должны выполнить обновление, то вы ДОЛЖНЫ перестроить все индексы, которые используют это (переиндексация обращений к таблице), и это может занять некоторое время ....

Оттуда мы можем:

CREATE FUNCTION growth(hits) RETURNS numeric immutable language sql as $$
     SELECT CASE WHEN ($1.last_update).number_hits = 0 THEN NULL 
                 ELSE $1.number_hits / ($1.last_update).number_hits
             END;
 $$;

Тогда мы можем:

SELECT h.growth -- or alternatively growth(h)
  FROM hits
 WHERE id = 12345;

И он автоматически его вычислит. Если мы хотим искать по росту, мы можем проиндексировать вывод:

CREATE INDEX hits_growth_idx ON hits (growth(hits));

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

SELECT * FROM hits WHERE growth = 1;

Может использоваться сканирование индекса по заранее заданным значениям.

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

1 голос
/ 10 июля 2011

Храните то, что вы не можете рассчитать быстро.

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

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