Задать вопрос
  • Как правильно реализовать структуру бд для многопользовательской платформы?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    У конструкторов типичный workload - около нуля на большинство площадок и небольшой процент активных. Заворачивать индивидуально каждого в свою БД - сильно утомительно в поддержке. Дожили до 1000 созданных сайтов (что не так уж много если не сказать "вообще крохи") - у вас 1000 баз, что уже весьма дофига. Выкатить в прод новую версию приложения - уже приключение.

    Если вы хотите SaaS - т.е. у конечных пользователей прямого доступа в БД нет никакого - то в поддержке сильно проще будет классическая схема шардирования. К тому же у вас данные разных клиентов заведомо по предметной области никак не пересекаются.
    - в таблицах специфичных для клиентов вводится site_id и входит в уникальные ключи и прочее счастье ограничений целостности (для postgresql можете дополнительно прикрутить row level security и база будет дополнительно приглядывать)
    - отдельно размещается ваш биллинг и управление пользователями, где помимо прочего пишете таблицу соответствия, какой site_id расположен на каком физическом хосте и в какой базе данных (плюс список ro-реплик)
    - закешировать соответствие сайта базе можно в каком-нибудь redis и ходить с одного единого пула серверов приложений что сильно проще по масштабированию приложения (если сервер приложения рассматривать как stateless, что опять же сильно проще в поддержке).

    В итоге схема позволяет работает с осмысленным числом крупных баз (начиная с одной и вводя новые по необходимости), неактивные сайты мигрировать в архивные базы, горячие от дорогих клиентов - выделять хоть даже в отдельную инфраструктуру. Кстати, фокус с отделением vip-клиента в отдельную инфраструктуру позволяет дать этому клиенту и прямой доступ в базу при необходимости и возможность пилить кастомный функционал именно для него.
    Ответ написан
  • Как в Mysql суммировать средние значения?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Просто добавьте ещё один select
    select sum(amount) from (
        select avg(/**/) as amount
        /* ... */
    ) total
    Ответ написан
  • Можно ли поставить разные таймзоны в типе datetime with timezone postgresql?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    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
    DBA Team для вашего PostgreSQL?
    но как переменная current_amount попадет внутрь триггера?

    Автор статьи не стал вдаваться в детали какой-либо СУБД, поэтому уточняйте в документации к своей СУБД.
    Для for each row триггеров обычно можно читать из NEW.amount в after insert триггерах.
    Для for each statement - смотрите документацию к своей СУБД.

    либо ограничить инсерты\апдейты (разрешив их только вызовами изнутри sql-сервера), но мне кажется, что sql-сервер не позволяет добавлять такие ограничения на таблицы

    Смотрите опять же документацию к своей СУБД.
    Для postgresql такую модель прав сделать можно. Для этого необходим отдельный пользователь для деплоя приложения (вообще полезная штука всегда) и security definer триггер.

    могут ли гарантировать триггеры целостность данных?

    Могут, но бывают сюрпризы. Например, mysql вам не запретит из триггера на ACID табличке что-то делать с myisam. Последующий rollback транзакции по любой причине = у вас потеря целостности. Впрочем, если вы знаете о целостности данных - то вы и не станете использовать всякое myisam.
    Ответ написан
    Комментировать
  • Почему не работает UNION ALL запрос?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Потому что имеет на то право.
    https://dev.mysql.com/doc/refman/5.7/en/union.html
    Use of ORDER BY for individual SELECT statements implies nothing about the order in which the rows appear in the final result


    select /*payload*/ from user
    where rank_golos >0
    order by rank_golos >=22.1 desc, 
      if (rank_golos >=22.1, rank_yearnub, rank_golos) desc,
      if (rank_golos >=22.1, rank_golos, rank_yearnub) desc

    Если типы rank_golos и rank_yearnub могут быть приведены к общему виду.
    Ответ написан
    2 комментария
  • Выбрать первую и последнюю запись группы?

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

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

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

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

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

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

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

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

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

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

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

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

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Один сегмент 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 комментария
  • Не могу понять что не так? json_decode почему не работает?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    $result = curl_exec($ch);
    if (!$result) {
    $result = curl_error($ch);
    }

    return $result;

    Оригинально. И нафига?

    Разделите мухи и котлеты. Что именно вам приходит в ответ после http запроса? Что именно вы передаёте json_decode?

    Спойлер: CURLOPT_RETURNTRANSFER
    Ответ написан
    4 комментария
  • Проблема с блоком питания, как решить???

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    напряжения измеряете хорошим мультиметром?
    Если смотрите софтовые показатели какого-то мониторинга - не обращайте внимания. Могут безбожно врать и показывать ничего общего с реальными электрическими характеристиками.

    Если мультиметр показывает 11,5В - это нормально и все потребители должны в номинальном режиме работать штатно. Стандарт ATX (2.01 для примера (стр 12), в остальных 2.х те же допуски) допускает 5% отклонения по +12В, т.е. от 11,4В до 12,6В

    (В любом замесе фпс дропается со 80 до 15, и после замеса восстанавливается). Хотя стресс тест аида64 всей системы проходит бесконечно долго

    Выглядит как защита от перегрева. Что с температурами под нагрузкой?
    Ответ написан
  • Какой размер резервной области жесткого диска HDD?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Если вам данные нужны - диск в утиль.
    Если не нужны - использовать дальше пока не пойдёт в утиль.
    В обоих случаях число ремапов и что будет после них - сугубо академический интерес.

    В наиболее подробной официальной доке таких сведений нет: https://www.seagate.com/staticfiles/support/disc/m...
    Вероятно не публикуется вовсе. 3000 ремапов помню на аналогичном seagate, без вопросов забрали по гарантии.
    Ответ написан
    2 комментария
  • Е5-2640v4 6 ядер ощутимо мощнее, чем Е5-1650v3 6 ядер или нет?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Странные участники вопроса.
    https://ark.intel.com/compare/82765,92984
    E5-1650V3 - 6 ядер + HT. Ну ладно, пусть в маркетинговом языке будет 12 ядер
    Но у E5-2640V4 ой как далеко не 6 ядер, а 10 + HT. Потому он и дороже.

    Ну а дальше вопрос к задачам. Еслии нужны высокочастотные ядра в малом количестве или побольше памяти - то конфиг с 1650V3 выглядит интереснее. Если надо побольше ядер на вычислительные задачи, но не так много памяти требуется - 2640V4 интереснее. (плюс учитывать, а сколько именно надо переплачивать)
    Ответ написан
    7 комментариев
  • PDO при bindValue выдаёт false?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    При чём тут bindValue?
    execute возвращает всегда boolean. php.net/manual/en/pdostatement.execute.php
    Разумеется у bool нет методов, это не объект.
    Ответ написан
    1 комментарий
  • Как сделать DELETE с вложенным SELECT`ом?

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Исторически mysql сообщает об ошибке синтаксиса начиная с того места, где эта ошибка случилась.
    Т.е. парсер mysql не умеет использовать алиас таблицы для delete запросов.

    Или, как следует из документации
    Table aliases in a multiple-table DELETE should be declared only in the table_references part of the statement. Elsewhere, alias references are permitted but not alias declarations.

    Возможно сделать вырожденный случай мультитабличного удаления с одной таблицей, тогда алиас для таблицы задать возможно:
    delete t from test as t where t.i = 100;
    Ответ написан
  • Как хранить базу postgres 8.4 в памяти?

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

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

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    надо выбрать все продукты по category_id

    WHERE product_id =

    Ну в самом же деле?

    Сходите отдохните, погулять или поспать.
    Ответ написан
    4 комментария
  • Как сделать правильно check constraint?

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

    Melkij
    @Melkij
    DBA Team для вашего PostgreSQL?
    Перепроверил догадку
    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 (без времени вовсе) надо сравнивать аккуратно.
    Ответ написан
    Комментировать