postgresql триггеры и прочее
а зачем тебе временные таблицы?
а зачем тебе временные таблицы?Чтобы вот так сделать:
create temp table tmp as select old.*;
execute 'insert into '||t_dst||' select * from tmp';
Если это можно сделать как-то по-другому, то говори. У меня просто не получилось. Если old в разных формах подсовывать в execute, то не получается.
У меня просто не получилось.не получается именно: в генеренном запросе использовать *.old?
если запрос негенеренный, то ок?
удаленные записи перекидываются в таблицу буфер
крутится job(процесс и т.д.) по таймеру(событиям, постоянно или еще как-то который берет порцию из буфера и ее обрабатывает, затем следующую порцию и т.д.
решение хорошо тем, что оно универсальное и легко масштабируется
соответственно твоя проблема в этом варианте уйдет
если запрос не генеренный, то ок?Ну вот этот запрос ведь не генерённый:
create temp table tmp as select old.*;
А в генерённый надо что-то хитрое, наверное сказать. В общем то, что я пробовал у меня не получилось. Сейчас ещё попробую разные комбинации.
Ну вот этот запрос ведь не генерённый:тут нет "insert into" в только что созданную таблицу
согласен, что притянуто, но практика показывает, что лучше проверить
часто, кстати, применяется вариант вида:А чем оно универсальнее и более масштабируемое, чем моё?
удаленные записи перекидываются в таблицу буфер
крутится job(процесс и т.д.) по таймеру(событиям, постоянно или еще как-то который берет порцию из буфера и ее обрабатывает, затем следующую порцию и т.д.
решение хорошо тем, что оно универсальное и легко масштабируется
соответственно твоя проблема в этом варианте уйдет
На самом деле у меня несколько таких таблиц и мне придётся несколько буферов делать и их обрабатывать отдельно. Да и удалять я буду нечасто. Просто хотел автоматизировать себе работу, чтобы руками всё не делать.
тут нет "insert into" в только что созданную таблицучего?
согласен, что притянуто, но практика показывает, что лучше проверить
execute 'insert into '||t_dst||' values '||row(old.*);
То будет вот такая ошибка:
DELETE FROM test.log where a=1;
ERROR: column "2011-02-01 00:00:00" does not exist
LINE 1: insert into test.log_2011 values ("2011-02-01 00:00:00",1)
^
QUERY: insert into test.log_2011 values ("2011-02-01 00:00:00",1)
CONTEXT: PL/pgSQL function "archive_deleted" line 10 at EXECUTE statement
Т.е. в сгенерённой командре строка оказывается в двойных кавычках. Что странно как-то.
А чем оно универсальнее и более масштабируемое, чем моё?масштабируемее - потому что пофигу сколько будет удаляться строк: 1 или миллион, решение все равно будет работать.
в твоем случае, мы видим - что от кол-ва строк зависит: решение работает или нет
ну а просто: insert into test.log_2011 from select *.old работает? если удалять записи за 2011
масштабируемее - потому что пофигу сколько будет удаляться строк: 1 или миллион, решение все равно будет работать.Ну я бы не сказал, что оно работает. Это можно считать не работает. Собственно поэтому его и надо исправить. Тогда не будет проблем с "масштабированием". Мне как раз миллионы строк и надо удалять.
в твоем случае, мы видим - что от кол-ва строк зависит: решение работает или нет
ну а просто: insert into test.log_2011 from select *.old работает? если удалять записи за 2011Точно сейчас не вспомню, но вроде как да. Ведь со временной таблицей это работает.
Точно сейчас не вспомню, но вроде как да. Ведь со временной таблицей это работаеттак ты все-таки найди точную грань когда с одной стороны у тебя еще работает, а с другой уже не работает.
действительно ли insert into test.log_2011 from select *.old у тебя работает,
а execute 'insert into test.log_2011 from select *.old' уже нет
действительно ли insert into test.log_2011 from select *.old у тебя работает,Так я же говорю, что со временной таблицей работает.
а execute 'insert into test.log_2011 from select *.old' уже нетТут не грань, а пропасть уже. Такое не работает, т.к. внутри execute, похоже, оно уже не знает про old. В ощибках оно не разворачивается, его тип не упоминается, просто ругается на него как на слово. Поэтому old должен быть неквотирован, но как-то корректно преобразован в строку.
Так я же говорю, что со временной таблицей работает.тебе лень проверить?
вдруг он тоже ругнется что он не понимает что такое .old, и ты вдруг, например, вспомнишь, что в postgree в insert-е select после from-а надо брать в скобки
тебе лень проверить?Не то, чтобы лень. Просто я уверен, что будет абсолютно аналогично как с временной таблицей.
вдруг он тоже ругнется что он не понимает что такое .old, и ты вдруг, например, вспомнишь, что в postgree в insert-е select после from-а надо брать в скобки
Ну ладно, проверил сейчас. Всё как я и говорю.
http://archives.postgresql.org/pgsql-general/2009-09/msg0117...
они, кстати, столкнулись с этим на той же задаче, что и ты
это не оно?Не совсем понял что там. Они какую-то совсем ебанутую конструкцию используют. Типа отквотированная неправильно запись приведённая к типу, а потом от неё звёздочку. Но у меня проблема в том, что я не могу привести к типу, т.к. его у меня нет.
http://archives.postgresql.org/pgsql-general/2009-09/msg0117...
они, кстати, столкнулись с этим на той же задаче, что и ты
Но у меня проблема в том, что я не могу привести к типу, т.к. его у меня нет.таблица - это разве не тип?
Они какую-то совсем ебанутую конструкцию используют. Типа отквотированная неправильно запись приведённая к типу, а потом от неё звёздочку. Но у меня проблема в том, что я не могу привести к типу, т.к. его у меня нет.А нет, получилось привести к таблице.
Т.е. это блядские двойные кавычки если приводить обратно к типу, то они пережуются уже нормально. Вот такой результат.
execute 'insert into '||t_dst||' select ('||quote_literal(OLD.*)||'::'||t_dst||').*';
Т.е. OLD приводится к тексту с двойными кавычками, далее это квотируется в строку, потом уже во внутренней команде эта строка преобразовывается обратно в строку для данной таблицы и из неё берутся поля для селекта. Ужоснах!
таблица - это разве не тип?Да вроде тип. Но в каком-то месте оно меня послало, когда я пытался пользоваться, но там может быть и с типом послало бы. Поэтому я сомневался.
Ужоснах!если у тебя в таблицах нет хитрых типов колонок и значения не очень длинные, то для твоей задачи должно прокатить
зы
только проверь на всякий случай, что там происходит, если в значении встречаются всякие разные кавычки и какие-нибудь страшные уникодные символы
если у тебя в таблицах нет хитрых типов колонок и значения не очень длинные, то для твоей задачи должно прокатитьА почему думаешь, что могут помешать. Оно же само их квотирует и расквотирует?
зы
только проверь на всякий случай, что там происходит, если в значении встречаются всякие разные кавычки и какие-нибудь страшные уникодные символы
Уже запустил удаляться 6 миллионов строк.
А почему думаешь, что могут помешать. Оно же само их квотирует и расквотирует?потому что в теории обычно все замечательно, а на практике кто-нибудь где-нибудь что-нибудь не доделал (как. например, old/new внутри execute)
(как. например, old/new внутри execute)Ну там уже другой контекст полечается. Так что может быть правильно не видно.
А так вообще строчки у меня все похожие и если на одних отработает, то и на других будет нормально.
...
insert into year2009 (...)
select old.* where old.year = 2009
insert into year2010 (...)
select old.* where old.year = 2010
PS А в постгре нет нормальных триггеров, чтоб вешать такое не на каждую строку, а на событие удаления? Ну, чтоб еще данные были доступны...
сделай явную вставку типаНе понял что там ты написал. Т.е. куда ты это предлагаешь засунуть.
Но я не хочу расписывать каждый год отдельно. Так бы я и руками бы удалил бы в таблицу. А мне лень.
PS А в постгре нет нормальных триггеров, чтоб вешать такое не на каждую строку, а на событие удаления? Ну, чтоб еще данные были доступны...Есть построчные триггеры, есть общие. Но я тоже не понимаю чем мне общий поможет. Т.к. там могут быть разные строчки. И кроме того этот триггер before delete, т.е. данные ещё доступны, если я понимаю про что ты.
2. В оракле есть триггеры собственно на событие, а есть for each row. Насколько мне известно, доступа к вставляемым данным в общих триггерах нет, поэтому приходится использовать построчные, и при больших объемах наступает всеобщий ппц. В мсскл нет построчных триггеров, данные доступны в псевдотаблицах inserted/deleted - срабатывает один раз на событие. Если такое есть в постгре - то надо делать так. Плюс если постгре как оракл поддерживает множественную вставку (один инсерт - много таблиц то вообще шикарно.
3. А тебе вообще нужны триггеры? Может, стоит сначала разложить данные по таблицам, а потом удалять? Или если стоит задача архивирования, тупо партиционировать таблицу?
1. На каждый год записать свою вставку. Я понимаю, что тебе лень, но годов не так и много + в конце концов скрипт для этого дела можно сгенерить на имеющиеся года + на 150 лет вперед, если собираешься все это время поддерживать. На скорость это почти не повлияет,Ну я не хотел так делать. Иначе бы этот вопрос не возник. Написать прямые запросы и скритп не составило бы труда. Но это не цель этого треда.
зато избавит тебя от создания временных таблиц, с которыми у тебя косякНу если ты до конца прочитал, то я от временной таблицы избавился.
2. В оракле есть триггеры собственно на событие, а есть for each row. Насколько мне известно, доступа к вставляемым данным в общих триггерах нет, поэтому приходится использовать построчные, и при больших объемах наступает всеобщий ппц. В мсскл нет построчных триггеров, данные доступны в псевдотаблицах inserted/deleted - срабатывает один раз на событие. Если такое есть в постгре - то надо делать так. Плюс если постгре как оракл поддерживает множественную вставку (один инсерт - много таблиц то вообще шикарно.Сейчас точно не скажу что там доступно с общим триггером. Но там придётся скрипт намного сложнее писать, т.к. надо сначала года выбрать какие там есть, потом генерировать для каждого команду. "Пипеца" на своих объёмах не наблюдаю сейчас с построчным триггером.
3. А тебе вообще нужны триггеры? Может, стоит сначала разложить данные по таблицам, а потом удалять?Я уже писал что я хочу сделать. Не хочу делать вручную. Я хотел сделать эту штуку, чтобы о ней потом можно было тупо забыть и она сама работала как надо.
Или если стоит задача архивирования, тупо партиционировать таблицу?Ну мне не особо надо это объединять в одно. Но собственно что-то вроде партиционирования и делается в результате. При партиционировании ведь тоже надо будет как-то по таблицам раскладывать. А там либо расписывать для каждого года отдельно, либо что-то подобное писать.
Оставить комментарий
tokuchu
У меня в таблице лежат события с датой. Я хочу сохранять их в "архивных" таблицах при удалении. Т.е. когда я удаляю запись, то она отправляется в архивную таблицу соответствующего года. Т.е. если в таблице log время у записи помечено 2010-м годом, то она должна попасть в таблицу log_2010 при удалении.В результате долгих потугов родился вот такой монстрик:
Оно работает, но если удалять много, то получаю ошибку:
Т.е. я так понимаю, что его смущает то, что создаётся много таблиц за транзакцию и не важно, что они удаляются. Есть у кого идеи как это можно исправить?