Обновить
0
0

Пользователь

Отправить сообщение

вместо дополнительной таблицы может быть можно воспользоваться gin индексом

CREATE INDEX idx_application_users ON application USING GIN((array[submitter_id,reviewer_id]));


Ну и сам запрос для поиска

select count(*)
from application
where array[:user_id] && array[submitter_id,reviewer_id]

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

Вот пример плана для такого запроса

Bitmap Heap Scan on ...  (cost=12.05..33.87 rows=6 width=892) (actual time=0.207..0.245 rows=3 loops=1)
  Recheck Cond: ('{360793003}'::numeric[] && ARRAY[idcreator, ideditor])
  Heap Blocks: exact=2
  ->  Bitmap Index Scan on ...  (cost=0.00..12.05 rows=6 width=0) (actual time=0.130..0.131 rows=3 loops=1)
        Index Cond: (ARRAY[idcreator, ideditor] && '{360793003}'::numeric[])
Planning Time: 0.624 ms
Execution Time: 0.352 ms

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

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

Если имелось ввиду про хранение, то все намного проще, int остается полноценным. Признак что в поле нет данных (Null) хранится в битовой маске перед самой записью. Таким образом если в записи есть Null, то само значение не записывается хранилище, но взводится флаг. Строка с Null занимает меньше памяти чем запись в которой записан 0 (битовая маска есть всегда). А еще извлечение подобных записей происходит быстрее, так как они более плотно упакованы на страницу, так что совет не использовать Null весьма спорный.

Один из примеров что были у меня - ведомости на начисление/удержание, все по заветам денормализации dPeriod (период расчета) и idCharge (Код оплаты) вынесены в Blt (Шапку ведомости)

Bltlist - содержит список сотрудников с суммами. Следующий запрос собирает информацию сколько сотрудник получил по указанному коду оплат в текущем расчетном периоде


```sql

select *

from

Blt

inner join Bltlist on

Blt.Id = BltList.IdBlt

where

Blt.dPeriod = '01.01.2024' and

Blt.idCharge = 10 and

Bltlist.idCard = 1000

```


PG читает из Bltlist по индексу idCard все записи с самих лохматых времен. Затем собирает все ведомости по индексу dPeriod, idCharge опять же все, в том числе где нашего сотрудника нет. затем делает хешджоин так как что слева что справа записей более 1000.


А теперь если делаем денормализацию и дублируем поля dPeriod, idCharge в Bltlist


```sql

select *

from

Blt

inner join Bltlist on

Blt.Id = BltList.IdBlt

where

Bltlist.dPeriod = '01.01.2024' and

Bltlist.idCharge = 10 and

Bltlist.idCard = 1000

```


Теперь PG по индексу dPeriod, idCharge, idCard читает только те записи, которые нам нужны ни каких лишних чтений

Мое понимание такое - В первом варианте сначала читается индекс и затем по каждой записи идет в основную таблицу. так как порядок записей совпадает, то страница не вытесняется из кеша и просто читается повторно из оперативной памяти.
Во втором случае все начинается так же, но так как сортировка индекса не совпадает с сортировкой в таблице, то происходит постоянный промах, а старые страницы вытесняются из кеша. В худшем случае приходится прочитать страницу данных для каждой записи + полный индекс.

Можно обратное число записывать, и в этом случае наоборот искать минимальное

В своем проекте сделал так, преобразование делается в набор | и пробелов, потом в отчетной системе или веб странички у строки делается межсимвольный интервал таким что бы две || соприкасались. Как итог не нужно было ни каких внешних библиотек все возвращала СУБД. Единственное ограничение в том что ограничен в высоте штрих кода.
Как то давно для своих проектов использовал такие макросы
#define digitalWriteC(pin,val)\
 if (val) { *((volatile uint8_t *) port_to_output_PGM[digital_pin_to_port_PGM[pin]]) |= (digital_pin_to_bit_mask_PGM[pin]);}\
 else {*((volatile uint8_t *) port_to_output_PGM[digital_pin_to_port_PGM[pin]]) &= ~(digital_pin_to_bit_mask_PGM[pin]);}

#define pinModeC(pin,mode)\
  if (mode == INPUT) { \
    *((volatile uint8_t *) port_to_mode_PGM[digital_pin_to_port_PGM[pin]]) &= ~(digital_pin_to_bit_mask_PGM[pin]);\
    *((volatile uint8_t *) port_to_output_PGM[digital_pin_to_port_PGM[pin]]) &= ~(digital_pin_to_bit_mask_PGM[pin]);\
  } else if (mode == INPUT_PULLUP) {\
    *((volatile uint8_t *) port_to_mode_PGM[digital_pin_to_port_PGM[pin]]) &= ~(digital_pin_to_bit_mask_PGM[pin]);\
    *((volatile uint8_t *) port_to_output_PGM[digital_pin_to_port_PGM[pin]]) |= (digital_pin_to_bit_mask_PGM[pin]);\
  } else {\
    *((volatile uint8_t *) port_to_mode_PGM[digital_pin_to_port_PGM[pin]]) |= (digital_pin_to_bit_mask_PGM[pin]);\
  };

inline uint8_t digitalReadC (uint8_t pin) __attribute__((always_inline));
uint8_t digitalReadC (uint8_t pin)
 {
   if (*((volatile uint8_t *) port_to_input_PGM[digital_pin_to_port_PGM[pin]]) & (digital_pin_to_bit_mask_PGM[pin])) {return HIGH;} else {return LOW;};  
 };


Работают корректно только если номера пинов и портов — константы. GCC всегда транслирует в sbi и cbi если это возможно. При этом Изменений в программе минимум. Всего то нужно использовать digitalWriteC вместо digitalWrite.

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность