По описанию внутренне похож на mbus, очередь так же хранится на таблицах. В mbus есть проблема, что при большом объеме (количесвтенном) передаваемых сообщений деградирует скорость чтения сообщений из-за большого числа мертвых записей (т.е. их удалили, но они остались на диске, автовакум не пришел еще или не может выполнить очистку). Как решили подобную проблему?
Если имелось ввиду про хранение, то все намного проще, int остается полноценным. Признак что в поле нет данных (Null) хранится в битовой маске перед самой записью. Таким образом если в записи есть Null, то само значение не записывается хранилище, но взводится флаг. Строка с Null занимает меньше памяти чем запись в которой записан 0 (битовая маска есть всегда). А еще извлечение подобных записей происходит быстрее, так как они более плотно упакованы на страницу, так что совет не использовать Null весьма спорный.
Один из примеров что были у меня - ведомости на начисление/удержание, все по заветам денормализации dPeriod (период расчета) и idCharge (Код оплаты) вынесены в Blt (Шапку ведомости)
Bltlist - содержит список сотрудников с суммами. Следующий запрос собирает информацию сколько сотрудник получил по указанному коду оплат в текущем расчетном периоде
```sql
select *
from
Blt
innerjoin 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
innerjoin Bltlist on
Blt.Id = BltList.IdBlt
where
Bltlist.dPeriod = '01.01.2024' and
Bltlist.idCharge = 10 and
Bltlist.idCard = 1000
```
Теперь PG по индексу dPeriod, idCharge, idCard читает только те записи, которые нам нужны ни каких лишних чтений
Мое понимание такое - В первом варианте сначала читается индекс и затем по каждой записи идет в основную таблицу. так как порядок записей совпадает, то страница не вытесняется из кеша и просто читается повторно из оперативной памяти. Во втором случае все начинается так же, но так как сортировка индекса не совпадает с сортировкой в таблице, то происходит постоянный промах, а старые страницы вытесняются из кеша. В худшем случае приходится прочитать страницу данных для каждой записи + полный индекс.
В своем проекте сделал так, преобразование делается в набор | и пробелов, потом в отчетной системе или веб странички у строки делается межсимвольный интервал таким что бы две || соприкасались. Как итог не нужно было ни каких внешних библиотек все возвращала СУБД. Единственное ограничение в том что ограничен в высоте штрих кода.
Работают корректно только если номера пинов и портов — константы. GCC всегда транслирует в sbi и cbi если это возможно. При этом Изменений в программе минимум. Всего то нужно использовать digitalWriteC вместо digitalWrite.
вместо дополнительной таблицы может быть можно воспользоваться gin индексом
Ну и сам запрос для поиска
Теперь для поиска будет использовать индекс, индекс поддерживается автоматически встроенными средствами.
Вот пример плана для такого запроса
Применять или нет - все зависит от бизнес задачи, так как запись тоже похожа на заклинание (хоть и попроще). 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 читает только те записи, которые нам нужны ни каких лишних чтений
Мое понимание такое - В первом варианте сначала читается индекс и затем по каждой записи идет в основную таблицу. так как порядок записей совпадает, то страница не вытесняется из кеша и просто читается повторно из оперативной памяти.
Во втором случае все начинается так же, но так как сортировка индекса не совпадает с сортировкой в таблице, то происходит постоянный промах, а старые страницы вытесняются из кеша. В худшем случае приходится прочитать страницу данных для каждой записи + полный индекс.
Можно обратное число записывать, и в этом случае наоборот искать минимальное
Работают корректно только если номера пинов и портов — константы. GCC всегда транслирует в sbi и cbi если это возможно. При этом Изменений в программе минимум. Всего то нужно использовать digitalWriteC вместо digitalWrite.