PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Заявката за Postgresql 9.4 става прогресивно по-бавна при присъединяване към TSTZRANGE с &&

Ограничение за изключване

Предлагам ви вместо това да използвате ограничение за изключване, което е много по-просто, по-безопасно и по-бързо:

Трябва да инсталирате допълнителния модул btree_gist първи. Вижте инструкции и обяснение в този свързан отговор:

И трябва да включите "ParentID" в таблицата "Лента" излишно, което ще бъде малка цена за плащане. Дефинициите на таблици могат да изглеждат така:

CREATE TABLE "Foo" (
   "FooID"    serial PRIMARY KEY
   "ParentID" int4 NOT NULL REFERENCES "Parent"
   "Details1" varchar
   CONSTRAINT foo_parent_foo_uni UNIQUE ("ParentID", "FooID")  -- required for FK
);

CREATE TABLE "Bar" (
   "ParentID"  int4 NOT NULL,
   "FooID"     int4 NOT NULL REFERENCES "Foo" ("FooID"),
   "Timerange" tstzrange NOT NULL,
   "Detail1"   varchar,
   "Detail2"   varchar,
   CONSTRAINT "Bar_pkey" PRIMARY KEY ("FooID", "Timerange"),
   CONSTRAINT bar_foo_fk
      FOREIGN KEY ("ParentID", "FooID") REFERENCES "Foo" ("ParentID", "FooID"),
   CONSTRAINT bar_parent_timerange_excl
      EXCLUDE USING gist ("ParentID" WITH =, "Timerange" WITH &&)
);

Също така промених типа данни за "Bar"."FooID" от int8 към int4 . Той препраща към "Foo"."FooID" , което е сериен , т.е. int4 . Използвайте съвпадащия тип int4 (или просто цяло число ) поради няколко причини, една от които е производителността.

Вече не се нуждаете от тригер (поне не за тази задача) и не създавате индекса "Bar_FooID_Timerange_idx" вече, тъй като е създаден имплицитно от ограничението за изключване.

Индекс на btree на ("ParentID", "FooID") все пак най-вероятно ще бъде полезно:

CREATE INDEX bar_parentid_fooid_idx ON "Bar" ("ParentID", "FooID");

Свързани:

Избрах UNIQUE ("ParentID", "FooID") а не обратното с причина, тъй като има друг индекс с водещ "FooID" в която и да е таблица:

Освен:Никога не използвам CaMeL в двойни кавички -идентификатори на случай в Postgres. Правя го тук само за да се съобразя с оформлението ви.

Избягвайте излишната колона

Ако не можете или не искате да включите "Bar"."ParentID" излишно, има още един измамник начин - при условие, че "Foo"."ParentID" никога не се актуализира . Уверете се в това, например с тригер.

Можете да фалшифицирате IMMUTABLE функция:

CREATE OR REPLACE FUNCTION f_parent_of_foo(int)
  RETURNS int AS
'SELECT "ParentID" FROM public."Foo" WHERE "FooID" = $1'
  LANGUAGE sql IMMUTABLE;

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

Още:

След това го използвайте в ограничението за изключване:

   CONSTRAINT bar_parent_timerange_excl
      EXCLUDE USING gist (f_parent_of_foo("FooID") WITH =, "Timerange" WITH &&)

Докато запазвате един излишен int4 колона, проверката на ограничението ще бъде по-скъпа и цялото решение зависи от повече предварителни условия.

Обработване на конфликти

Можете да обвиете INSERT и АКТУАЛИЗИРАНЕ във функция plpgsql и улавяне на възможни изключения от ограничението за изключване (23P01 exclusion_violation ), за да го обработите по някакъв начин.

INSERT ...

EXCEPTION
    WHEN exclusion_violation
    THEN  -- handle conflict

Пълен примерен код:

Обработване на конфликти в Postgres 9.5

В Postgres 9.5 можете да управлявате INSERT директно с новата реализация "UPSERT". Документацията:

Въпреки това:

Но все още можете да използвате ПРИ КОНФЛИКТ НЕ ПРАВЕТЕ НИЩО , като по този начин се избягва възможно exclusion_violation изключения. Просто проверете дали някои редове са действително актуализирани, което е по-евтино:

INSERT ... 
ON CONFLICT ON CONSTRAINT bar_parent_timerange_excl DO NOTHING;

IF NOT FOUND THEN
   -- handle conflict
END IF;

Този пример ограничава проверката до даденото ограничение за изключване. (Наименувах ограничението изрично за тази цел в дефиницията на таблицата по-горе.) Други възможни изключения не се улавят.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL:count() или поддържане на брояч?

  2. Група за улавяне на регулярен израз на PostgreSQL в select

  3. Приложение за наблюдение на PostgreSQL заявки в реално време?

  4. Конфигурирайте STS с JPA 2.0 с помощта на PostgreSQL 9.3

  5. Как да конвертирате json масив в postgres int масив в postgres 9.3