Ответы пользователя по тегу PostgreSQL
  • Можно ли поставить разные таймзоны в типе datetime with timezone postgresql?

    Melkij
    @Melkij
    PostgreSQL DBA
    timestamp with time zone приводит и хранит данные только в UTC и переводит их в местное время при чтении согласно сессионной настройке timezone.

    https://www.postgresql.org/docs/9.6/static/datatyp...
    For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, and is converted to UTC using the offset for the timezone zone.


    timestamp without time zone вовсе игнорирует указание в литерале временной зоны.

    а других timestamp и нет. Поэтому нет, хранить таймзону (при необходимости в этом) необходимо отдельно. Зато за счёт этого timestamp занимает всего константные 8 байт.
    Ответ написан
    Комментировать
  • Выбрать первую и последнюю запись группы?

    Melkij
    @Melkij
    PostgreSQL DBA
    В смысле вот так?
    select ticket_number , min(some_id), max(some_id) from tablename group by ticket_number
    Ответ написан
  • Pgpool2 multy-master mode где искать мануалы по настройке? Как вы масштабируете базу(под запись)?

    Melkij
    @Melkij
    PostgreSQL DBA
    Как вы масштабируете базу(под запись)?

    В основном никак. У нас нет баз на столько десятков террабайт данных чтобы внятно настроенный единственный мастер с парой обычных потоковых ro-реплик не справлялся.

    Если у вас столько данных пишется что одного мастера действительно мало - то репликация вам не подходит по своему определению, она не про масштабирование записи, а только чтения и high availability (репликация = копия. Копию нельзя сделать, если писать не все данные).

    А те базы что у нас распиливались - распиливались они не потому что в мастер упёрлись:
    Что-то пилится на горячее-архивное: отдельные одна или несколько машин на более дешёвых (медленных) дисках, куда переносятся данные старше какого-то времени, к которым обращаются редко.
    Что-то пилится на части функционально. Например, сайт - один кластер, данные для окружающих некритичных сервисов - другой кластер. Или данные ru-сайта - один кластер, данные нескольких других стран - отдельные базы на другом кластере.

    Ещё можно пилить по каким-нибудь другим динамическим критериям. Например, данные всех пользователей от 1 до 1000 - на один кластер, от 1000 до 2000 - на другой. Плюс пара машин с данными координатора какой id на какой машине и авторизации. Это уже эталонное горизонтальное масштабирование. Крайне редко кому действительно нужно и собирается типично вручную с пониманием что и зачем делается.

    Сильно ли нагружает сервер процес синхронной репликация?

    Железо - не очень. Со стороны приложения кажется что очень. Потому что латентность коммита локально и согласовать коммит с даже хотя бы одной синхронной репликой - вещи очень сильно расходящиеся по латентности.

    чаще всего используеться репликация на уровне приложения

    Репликация чаще всего используется штатная потоковая.
    Запросы от приложения удобнее направлять именно из приложения не из-за сырости прокси, а потому что именно приложению лучше знать, нужно ли запрос отправлять на реплику (и если реплику - то какую, боевую? отдельную для медленных запросов аналитики?) или его вообще можно выполнять только на мастере.

    какие есть угрозы при такой балансировке базы?

    В смысле при мультимастере? Кучу головной боли вам доставит CAP теорема, из-за которой внятного мультимастера нет.
    Самое весёлое - split brain, когда у вас образовались противоречащие друг другу данные на двух мастерах.
    Или триггерная репликация внезапно встала колом и надо разбираться, из-за чего.
    Отправлять пишущие запросы синхронно на несколько хостов и предполагать, что там будут сходиться данные в итоге - это надо быть или большим оптимистом или очень внимательно проверять каждый запрос на предмет что именно он будет делать и как себя поведёт при конкурентном доступе.
    Ответ написан
    4 комментария
  • Postgresql как ограничить общий размер WAL-файлов?

    Melkij
    @Melkij
    PostgreSQL DBA
    Один сегмент WAL обычно имеет фиксированный размер 16мб (опция компиляции postgresql with-wal-segsize, если вы её указывали - вы должны об этом знать, плюс она требует initdb делать заново). Поэтому их количество пересчитывается в объём банальным умножением.

    Ограничить максимальный занимаемый объём wal сверху - нельзя. Такой единой гайки нет, даже если вас устраивает переход базы в readonly по достижении этого лимита. И есть довольно много гаек, которые при своём использовании могут попросить базу не вычищать старые wal ещё какое-то время.

    Гайки, на которые надо обращать внимание:
    wal_keep_segments - база оставляет на диске не меньше этого числа wal, что позволяет реплике штатно на некоторое время терять мастера и затем догонять
    replication slots - если вы сделаете слот репликации и его никто не будет читать - база будет сохранять wal пока не закончится диск. Если вы используете слоты репликации, то у вас в мониторинге обязана быть отдельная проверка что слот вычитывается
    max_wal_size - несмотря на название - объём wal, по накоплению которого происходит checkpoint. (либо по таймеру checkpoint_timeout смотря что случится раньше). Реально объём wal может быть выше, т.к. автоматический checkpoint намеренно не выполняется моментально, а размазан во времени.
    min_wal_size - этот объём wal всегда будет на диске занят и будет переписываться по кругу. Как гарантия того, что на диске есть место под столько wal
    archive_command - если включен и команда возвращает ненулевой статус возврата - то будет накапливать wal без ограничений. wal будут удалены (если только ещё не нужны какой из других настроек) когда archive_command получает от команды 0 код возврата.

    Если не хочется много денег тратить на резерв свободного места на хороших SSD - разместите на SSD саму базу данных, а WAL перенесите (симлинком директории pg_xlog (до 10.0) или pg_wal (10.0 и выше)) на отдельные HDD. WAL пишутся строго последовательно, вполне возможно жить с WAL на механических дисках и держать хорошую нагрузку.
    Плюс если работаете не с деньгами, можно сделать synchronous_commit = off. Что увеличит производительность всех пишущих транзакций. Но в случае фатального краха железа вы потеряете последние 3*wal_writer_delay транзакции (т.е. до 3*200мс = 600мс).
    Ответ написан
    2 комментария
  • Как хранить базу postgres 8.4 в памяти?

    Melkij
    @Melkij
    PostgreSQL DBA
    Закупаете железку с 256гб ram и выше. Ставите shared_buffers в 200гб. Всё. Со временем все данные к каким обращались будут подтянуты в память. А поскольку буферов больше чем база - база их не будет вытеснять из памяти.

    Можно было бы воспользоваться pg_prewarm для более удобного подтягивания данных в память после старта СУБД - да у вас какая-то ископаемая, давно уже не поддерживаемая версия. pg_prewarm для такой древности нет. (если, конечно, вы не опечатались в 9.4)
    Для такого объёма shared_buffers желательно huge pages сделать по объёму на пару процентов больше чем shared_buffers. А вот как - может для 8.4 и никак, я не настолько старый DBA, не знаю.
    Ответ написан
    4 комментария
  • Как сделать правильно check constraint?

    Melkij
    @Melkij
    PostgreSQL DBA
    next_month := date_part( 'year', NEW.dtime)::text ||'-'|| date_part( 'month', NEW.dtime )::text ||'-31';

    Какой удивительно-непроверенный способ выстрелить себе в ногу. Половина года просто не нужна? Ни февраль ни ноябрь?

    При этом же
    table_part := table_master
    || '' || to_char(NOW(), 'YYYY')::text
    || 'm' || to_char(NOW(), 'MM')::text;

    INSERT INTO ' || table_part || '
    Какой дважды отважный способ отстрелить ногу. Дебажить что у вас получается не пробовали в принципе?
    И с чего же это действительно violates check constraint? Вообще не понятно. И вас ничего на насторожило даже в попытке вставить августовские данные в m10 раздел? Ну нельзя же так, в самом деле.

    Про race condition не упоминаю даже, он хотя бы действительно не для всех применений имеет значение.
    Ответ написан
  • Как работать с Ltree?

    Melkij
    @Melkij
    PostgreSQL DBA
    Это реализация материализованного пути. Ветка удалена если в ней нет элементов. Перенос - перенести каждый элемент. subpath функция в помощь например
    update tablename set tree = concat('newbranch.', subpath(tree, 1))::ltree where tree <@ 'origbranch';
    Ответ написан
    Комментировать
  • Как ограничить поиск в партиции таблицы?

    Melkij
    @Melkij
    PostgreSQL DBA
    Перепроверил догадку
    melkij=> create table events2016m11 (check (dtime >= '2016-11-01'::date AND dtime < '2016-12-01'::date)) inherits(events);
    melkij=> insert into events2016m11 values ('2016-11-20');
    INSERT 0 1
    melkij=> explain (analyze) select * from events where dtime > '2016-12-05';
                                                       QUERY PLAN                                                   
    ----------------------------------------------------------------------------------------------------------------
     Append  (cost=0.00..38.25 rows=754 width=8) (actual time=0.013..0.013 rows=0 loops=1)
       ->  Seq Scan on events  (cost=0.00..0.00 rows=1 width=8) (actual time=0.004..0.004 rows=0 loops=1)
             Filter: (dtime > '2016-12-05 00:00:00+03'::timestamp with time zone)
       ->  Seq Scan on events2016m11  (cost=0.00..38.25 rows=753 width=8) (actual time=0.009..0.009 rows=0 loops=1)
             Filter: (dtime > '2016-12-05 00:00:00+03'::timestamp with time zone)
             Rows Removed by Filter: 1
     Planning time: 0.127 ms
     Execution time: 0.032 ms
    (8 строк)
    melkij=> drop table events2016m11 ;
    DROP TABLE
    melkij=> create table events2016m11 (check (dtime >= '2016-11-01'::timestamptz AND dtime < '2016-12-01'::timestamptz)) inherits(events);
    CREATE TABLE
    melkij=> insert into events2016m11 values ('2016-11-20');INSERT 0 1
    melkij=> explain (analyze) select * from events where dtime > '2016-12-05';                                              QUERY PLAN                                              
    ------------------------------------------------------------------------------------------------------
     Append  (cost=0.00..0.00 rows=1 width=8) (actual time=0.004..0.004 rows=0 loops=1)
       ->  Seq Scan on events  (cost=0.00..0.00 rows=1 width=8) (actual time=0.004..0.004 rows=0 loops=1)
             Filter: (dtime > '2016-12-05 00:00:00+03'::timestamp with time zone)
     Planning time: 0.301 ms
     Execution time: 0.024 ms
    (5 строк)
    
    melkij=> show constraint_exclusion ;
     constraint_exclusion 
    ----------------------
     partition

    Внимательнее с явным приведением типов. У планировщика достаточно работы и не всё эквивалентное он считает идентичным. К тому же timestamp with timezone и date (без времени вовсе) надо сравнивать аккуратно.
    Ответ написан
    Комментировать
  • Как посмотреть существующие триггеры событий (Event Trigger, postgresql)?

    Melkij
    @Melkij
    PostgreSQL DBA
    Они прописываются в системной view pg_event_trigger
    https://www.postgresql.org/docs/9.6/static/catalog...

    В psql есть сокращение \dy выполняющее вот такой запрос:
    SELECT evtname as "Name", evtevent as "Event", pg_catalog.pg_get_userbyid(e.evtowner) as "Owner",
     case evtenabled when 'O' then 'enabled'  when 'R' then 'replica'  when 'A' then 'always'  when 'D' then 'disabled' end as "Enabled",
     e.evtfoid::pg_catalog.regproc as "Procedure", pg_catalog.array_to_string(array(select x from pg_catalog.unnest(evttags) as t(x)), ', ') as "Tags"
    FROM pg_catalog.pg_event_trigger e ORDER BY 1
    Ответ написан
    Комментировать
  • Как правильно написать двойное обновление?

    Melkij
    @Melkij
    PostgreSQL DBA
    Вы сильно заблуждаетесь, если думаете, что ваш cte выполняется последовательно.
    The sub-statements in WITH are executed concurrently with each other and with the main query. Therefore, when using data-modifying statements in WITH, the order in which the specified updates actually happen is unpredictable. All the statements are executed with the same snapshot (see Chapter 13), so they cannot "see" one another's effects on the target tables.

    https://www.postgresql.org/docs/9.6/static/queries...

    Вы выполняете на одном слепке данных одних и тех строк различающиеся действия. Не надо так. Я понятий не имею, какой эффект от этого будет.
    К тому же вы элементарно переписываетесь в один просто запрос
    UPDATE "TABLE1"
    SET
      "Value2" = (NOT EXISTS(
        SELECT NULL
        FROM "TABLE2"
        WHERE "что-то" = "кое-что"
    )
          AND NOT EXISTS(
        SELECT NULL
        FROM "TABLE3"
        WHERE "что-то" = "кое-что"
    ))
    WHERE "кое-что" = ANY ($1 :: INT [])
    Ответ написан
    Комментировать
  • На чем делать кластер postgres?

    Melkij
    @Melkij
    PostgreSQL DBA
    Для начала задаёте себе и отвечаете на вопрос "зачем?"
    Потому что геморроя, проблем и граблей очень много. Бонусы - сомнительны. Основной пласт проблем - как решить, что пора переключать мастер на другой хост, а не вернётся старый мастер из-за недолгого (а то и вовсе планового) лага сети? Это организационный вопрос и автоматикой он не решается. Самое счастье с автоматикой - схлопотать split brain и получить на этом долгий и увлекательный квест "как бы разъехавшиеся данные теперь подружить воедино"
    мастер-мастер = головная боль перманентно. Потому что фундаментальная CAP теорема, которую никто пока внятно не решил. Или у вас проблемы с консистентностью или с медленной из-за распределённых транзакций записью.

    Автоматика для failover'а, которую я не придумал как спровоцировать на split brain - patroni. Вроде работает. Но в продакшене видел пока только однажды.

    Процедуры (да и вообще запросы) имеет смысл делить:
    - пишущие. Любые, какие что-то пишут в базе (включая create temporary table). Это должны роутиться строго на мастер
    - читающие. Идут на реплики
    - долго читающие. Идут на отдельные slow реплики, которые могут заметно отставать от мастера, но которые не будут мешать деятельности проекта
    Ответ написан
    4 комментария
  • Как при запросе получить в ячейке больший объем символов?

    Melkij
    @Melkij
    PostgreSQL DBA
    pg_stat_activity.query ограничен сверху конфигурационным параметром track_activity_query_size. Дефолтно 1024 байта.

    PS: current_query оно называлось до postgresql 9.2, которые уже давно EOL и сам 9.2 уже EOL. Планируйте обновление.
    Ответ написан
  • Ошибки при восстановлении dump?

    Melkij
    @Melkij
    PostgreSQL DBA
    Судя по всему вы делали дамп без --clean и пытаетесь восстановить в уже не пустую базу.
    Ответ написан
  • Какая база луче подойдет на рабочий портал?

    Melkij
    @Melkij
    PostgreSQL DBA
    Сейчас разработчики пишут портал

    Вот у разработчиков и спрашивайте, какую СУБД они лучше знают. И админов своих спросите, какую СУБД те лучше знают. DBA у вас явно нет, иначе вопрос бы так не стоял.

    Сам headhunter использует postgresql. Но там и своя команда админов классная, и вдобавок опытная команда DBA моих нынешних коллег, специализирующихся именно на postgresql.

    Я достаточно хорошо знаю обе СУБД с точки зрения разработчика, но не умею админить mysql, так что моё мнение будет предвзятым.
    Если делаете коммерческий проект - то используйте ту СУБД, которую лучше знает ваша команда. Если разработчики попрятались за своими ORM'ами и носу не заглядывают в базу - то без разницы, в таких условиях любая СУБД будет работать одинаково плохо. Если же хоть кто-то в команде понимает, что надо делать с базой - доверьте выбор ему и поинтересуйтесь о причинах выбора.
    Ответ написан
    Комментировать
  • Как перенести базу postgresql из нерабочей системы, если в chroot сервис не запускается?

    Melkij
    @Melkij
    PostgreSQL DBA
    Найдите, где datadir базы. Скорей всего /var/lib/postgresql/(версия базы)/main, но могла была быть перемещена, так же может стоять несколько кластеров базы и разные версии базы - в дебианах и убунтах это делается легко.

    Далее установить на новой системе postgresql идентичной major версии и не ниже minor версии что была там. Какая была major версия - смотрите файлик PG_VERSION в datadir. minor версию ставьте последнюю актуальную.
    Так понимаю, старая система в принципе не работает? Т.е. старая база выключена? Выключите и новую (пока пустую) базу. Проверьте, если не уверены, обе базы должна быть выключена.
    Переименовываете datadir на новом сервере (вообще, можно удалить, но можно и ошибиться консолью и дропнуть не то =) )
    Копируете каталог базы: rsync -a /olddatadir /newdatadir
    Копируете и правите если надо конфиги из /etc/postgresql/версия_базы
    Если каталог pg_tblspc/ в datadir не пуст - скопируйте и симлинки из него и все данные по этим симлинкам в аналогичные места на новой машине.
    Если pg_xlog/ является симлинком - его необходимо скопировать. Можно оставить симлинком, можно содержимое перекопировать.
    Пробуете запустить базу на новом месте. Смотрите в логи. Если на старом месте база не была повреждена (и ничего нужного скопировать не забыли) - то она запустится.
    Ответ написан
    1 комментарий
  • Как мне установить ограничение-проверки на два условия?

    Melkij
    @Melkij
    PostgreSQL DBA
    Для перечислений можно использовать родной enum
    melkij=> create type gender as enum('M','W');
    CREATE TYPE
    melkij=> create table foo (f gender);
    CREATE TABLE
    melkij=> insert into foo values('M');
    INSERT 0 1
    melkij=> insert into foo values('F');
    ОШИБКА:  неверное значение для перечисления gender: "F"
    СТРОКА 1: insert into foo values('F');
                                     ^
    melkij=> insert into foo values('');
    ОШИБКА:  неверное значение для перечисления gender: ""
    СТРОКА 1: insert into foo values('');

    И явный check не нужен и добавлять значения проще, особенно если поле используется не в одном месте базы только.
    Ответ написан
    Комментировать
  • Как быстро удалить большое количество строк в postgresql?

    Melkij
    @Melkij
    PostgreSQL DBA
    Безопасный подход для больших таблиц:
    create unlogged table list_for_delete (id int);
    insert into list_for_delete values ....
    
    with to_rm as (
        select id from list_for_delete limit 10000
    ), rm as (
        delete from list_for_delete where id in (select id from to_rm)
    )
    delete from tablename  where id in (select id from to_rm);
    
    vacuum analyze tablename;
    drop table list_for_delete ;

    cte с delete повторять пока не будет affeted rows = 0. Смотреть на лаг репликации, добавлять задержки между запросами и увеличивать/уменьшать размер пачки в зависимости от влияния на прод.
    vacuum в конце, можно после половины пройтись дополнительно. С таким-то объёмом можно руками вакуум вообще не делать и оставить автовакууму. А для таблиц побольше при массовом изменении имеет смысл.
    Ответ написан
    Комментировать
  • PostgreSQL 9.4.9. Текстовая колонка: какие-то значения были добавлены как string, другие как integer- может ли это привести к значения NULL?

    Melkij
    @Melkij
    PostgreSQL DBA
    Как добавляли, так и будет храниться и читаться.
    postgres=# create schema garage;
    CREATE SCHEMA
    postgres=# CREATE TABLE garage.users
    (
    car_id text COLLATE pg_catalog."default"
    )
    WITH (
    OIDS = FALSE
    )
    TABLESPACE pg_default;
    CREATE TABLE
    postgres=# insert into garage.users values ('1'), ($$'1'$$), (null);
    INSERT 0 3
    postgres=# select car_id, car_id is null from garage.users ;
     car_id | ?column? 
    --------+----------
     1      | f
     '1'    | f
            | t
    Ответ написан
    Комментировать
  • Чем бекапить все базы Postgres без прерывания доступа к сервису?

    Melkij
    @Melkij
    PostgreSQL DBA
    pg_basebackup
    Сделает консистентную физическую копию базы. Соответственно размер бекапа примерно равен размеру кластера postgresql + накопленные за время копирования WAL.
    Восстанавливаться элементарно запустив postgresql с указанием PGDATA в место где лежит результат pg_basebackup.
    Им обычно реплики поднимают.

    pg_dump или pg_dumpall
    Логический бекап данных. Обычно не очень подходит по критерию быстро восстанавливаться т.к. при восстановлении будут перестраивать индексы, проверять fk и прочие constraint, зато как правило сильно (в пару раз без сжатия легко, со сжатием ещё больше разница) компактнее по размеру бекапа

    Все из штатной поставки Postgresql. И другие способы бекапа Postgresql в основе своей опираются на них же.
    Ответ написан
    1 комментарий
  • Как извлечь данные из JSON?

    Melkij
    @Melkij
    PostgreSQL DBA
    Если не нужен join со значениями, а только фильтр - то
    where array(select (j->>'category_id')::int from jsonb_array_elements(data->'items') j) && array[1,3,5];

    Можно загнать подзапрос с построением массива в immutable хранимку и повесить по ней gin или gist индекс.
    Ответ написан
    Комментировать