Если руководство, в первую очередь финдир при согласовании с главбухом, приняли решения возложить некоторые операции необходимые для управленческого и финансового учёта на бухгалтера - будет делать, как миленький. Проверено неоднократно в McDonalds, P&G, Bunge, Siemens и многих других компаниях, где я так или иначе принимал участие во внедрении ERP.
Ключевое - сейчас.
Бухгалтерский учёт - лишь ничтожная часть планирования ресурсов предприятия. И то, что 1С уже очень давно (с 2013 года) пытается из бухгалтерии сделать ERP без кардинального пересмотра архитектуры - это их проблемы.
Вы вообще всё перепутали. Одна из основных причин прокрастинации - физиологическая. Перегруженность работой, усталость и недостаток сна заставляют экономить ресурсы. Остальные причины - перфекционизм, страх неудачи и скучная рутина, так же не имеют никакого отношения ни к зажиточности, ни к условному изобилию.
можно вернуться к Стругацким и их "Граду Обречённому"
В том же "Граде обреченном" немало героев, которых заботило далеко не только еда, питьё и жильё. Так что плохой пример.
Вы слышали о такой массовой болезни, как "прокрастинация"? это вот оно - реакция на отсутствие необходимости бороться.
Вообще связи не вижу. При чем тут откладывание важных дел? Если человек вместо важной работы занимается любимым делом (музыкой, фотографией, спортом и т.п.) - он лишь перенаправляет свои усилия в другом направлении.
Объясняю, очень сильно упрощая. Есть справочник вагонов:
CREATE TABLE cars (
id integer PRIMARY KEY,
accure_date date NOT NULL, -- дата акта получения
dismiss_date date NULL, -- дата акта выбытия
max_mileage integer -- максимальный пробег до планового ремонта
);
Есть рейсы вагонов:
CREATE TABLE hauls (
car_id integer REFERENCES cars,
out_date datetimetz NOT NULL, -- дата отправления
haul_mileage integer NOT NULL -- пробег в рейсе
);
Задача - вывести для каждого вагона, доступного на текущую дату (между accure_date и dismiss_date) остаточный пробег до планового ремонта, как разницу между максимальным пробегом и пробегом во всех совершенных им рейсов с момента акта получения вагона. С учётом того, что в наличии есть вагоны, которые после покупки, взятия в аренду или получения их по доверенности ещё не совершали рейсов. И таких вагонов у крупных операторов ежедневно сотни.
Искать затем, что “когда-то я работал в компании” - это 10+ лет. Сейчас я с SQL работаю сильно меньше и примера готового все равно не имею.
Во-первых, сразу видим несоответствие между
Попросил ИИ подобрать пример
и
Объемы - сотни GB, под террабайт базы бывали.
Ну и, как следствие, у AI возникла галлюцинация и он вставил в таблицу metrics_nullable множество нулей, хотя их там быть не должно.
Для информации, у меня только одна таблица истории дислокаций вагонов больше двух терабайт. DWH же суммарно давно петабайт преодолел.
Во-вторых, добавлять сюда размер индексов некорректно, так как обсуждался размер кортежей.
Во-третьих, я писал "в некоторых случаях", из чего следует, что могу привести пример.
Пожалуйста
CREATE TABLE metrics_nullable (
id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
value1 decimal(18,2),
value2 decimal(18,2),
value3 decimal(18,2),
value4 decimal(18,2),
value5 decimal(18,2),
value6 decimal(18,2),
value7 decimal(18,2),
value8 decimal(18,2),
value9 decimal(18,2),
value10 decimal(18,2),
value11 decimal(18,2),
value12 decimal(18,2),
value13 decimal(18,2),
value14 decimal(18,2),
value15 decimal(18,2),
value16 decimal(18,2)
);
CREATE TABLE metrics_fixed (
id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
value1 decimal(18,2) NOT NULL DEFAULT 0,
value2 decimal(18,2) NOT NULL DEFAULT 0,
value3 decimal(18,2) NOT NULL DEFAULT 0,
value4 decimal(18,2) NOT NULL DEFAULT 0,
value5 decimal(18,2) NOT NULL DEFAULT 0,
value6 decimal(18,2) NOT NULL DEFAULT 0,
value7 decimal(18,2) NOT NULL DEFAULT 0,
value8 decimal(18,2) NOT NULL DEFAULT 0,
value9 decimal(18,2) NOT NULL DEFAULT 0,
value10 decimal(18,2) NOT NULL DEFAULT 0,
value11 decimal(18,2) NOT NULL DEFAULT 0,
value12 decimal(18,2) NOT NULL DEFAULT 0,
value13 decimal(18,2) NOT NULL DEFAULT 0,
value14 decimal(18,2) NOT NULL DEFAULT 0,
value15 decimal(18,2) NOT NULL DEFAULT 0,
value16 decimal(18,2) NOT NULL DEFAULT 0
);
INSERT INTO metrics_nullable (value1, value2, value3, value4, value5,
value6, value7, value8, value9, value10, value11, value12, value13,
value14, value15, value16)
SELECT
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END,
CASE WHEN random() < 0.01 THEN (random()*1000+1)::int END
FROM generate_series(1, 1000000) AS gs(i);
INSERT INTO metrics_fixed (value1, value2, value3, value4, value5,
value6, value7, value8, value9, value10, value11, value12, value13,
value14, value15, value16)
SELECT
COALESCE(value1, 0),
COALESCE(value2, 0),
COALESCE(value3, 0),
COALESCE(value4, 0),
COALESCE(value5, 0),
COALESCE(value6, 0),
COALESCE(value7, 0),
COALESCE(value8, 0),
COALESCE(value9, 0),
COALESCE(value10, 0),
COALESCE(value11, 0),
COALESCE(value12, 0),
COALESCE(value13, 0),
COALESCE(value14, 0),
COALESCE(value15, 0),
COALESCE(value16, 0)
FROM metrics_nullable;
SELECT 'nullable' AS table_type, pg_size_pretty(pg_relation_size('metrics_nullable')) AS total_size
UNION ALL
SELECT 'fixed', pg_size_pretty(pg_relation_size('metrics_fixed'));
EXPLAIN ANALYZE
SELECT
sum(value1), sum(value2), sum(value3), sum(value4), sum(value5),
sum(value6), sum(value7), sum(value8), sum(value9), sum(value10),
sum(value11), sum(value12), sum(value13), sum(value14), sum(value15), sum(value16)
FROM metrics_nullable;
Finalize Aggregate (cost=27381.80..27381.81 rows=1 width=512) (actual time=79.031..80.915 rows=1.00 loops=1)
Buffers: shared hit=5548
-> Gather (cost=27381.39..27381.60 rows=2 width=512) (actual time=78.888..80.894 rows=3.00 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=5548
-> Partial Aggregate (cost=26381.39..26381.40 rows=1 width=512) (actual time=75.819..75.820 rows=1.00 loops=3)
Buffers: shared hit=5548
-> Parallel Seq Scan on metrics_nullable (cost=0.00..9714.67 rows=416667 width=80) (actual time=0.004..13.483 rows=333333.33 loops=3)
Buffers: shared hit=5548
Planning Time: 0.091 ms
Execution Time: 80.959 ms
EXPLAIN ANALYZE
SELECT
sum(value1), sum(value2), sum(value3), sum(value4), sum(value5),
sum(value6), sum(value7), sum(value8), sum(value9), sum(value10),
sum(value11), sum(value12), sum(value13), sum(value14), sum(value15), sum(value16)
FROM metrics_fixed;
Finalize Aggregate (cost=27439.68..27439.69 rows=1 width=512) (actual time=133.084..135.022 rows=1.00 loops=1)
Buffers: shared hit=10310
-> Gather (cost=27439.09..27439.40 rows=3 width=512) (actual time=132.909..134.984 rows=4.00 loops=1)
Workers Planned: 3
Workers Launched: 3
Buffers: shared hit=10310
-> Partial Aggregate (cost=26439.09..26439.10 rows=1 width=512) (actual time=129.484..129.485 rows=1.00 loops=4)
Buffers: shared hit=10310
-> Parallel Seq Scan on metrics_fixed (cost=0.00..13535.81 rows=322581 width=48) (actual time=0.005..10.629 rows=250000.00 loops=4)
Buffers: shared hit=10310
Planning Time: 0.091 ms
Execution Time: 135.067 ms
В-четвертых, проблема не столько в тупой выборке с суммированием, сколько в том, что NULL поле не требует поиска в индексе справочника, тогда как 0 - требует.
Поэтому имеем в результате
CREATE TABLE stations (
id integer PRIMARY KEY, -- идентификатор станиции
name varchar NOT NULL -- наименование станции
);
INSERT INTO stations (id, name)
SELECT G.i, G.i::text
FROM generate_series(1,40000) G(i)
UNION ALL
SELECT 0, '-- отсутствует --';
DROP TABLE hauls_fixed;
DROP TABLE hauls_nullable;
CREATE TABLE hauls_nullable (
id serial PRIMARY KEY,
from_staion_id integer NOT NULL REFERENCES stations, -- станция отправления
to_staion_id integer NOT NULL REFERENCES stations, -- станция назначения
border_station_id integer NULL REFERENCES stations, -- станция пересечения границы
export_station_id integer NULL REFERENCES stations, -- станция экспортного досмотра
import_station_id integer NULL REFERENCES stations -- станция импортного досмотра
);
INSERT INTO hauls_nullable (from_staion_id, to_staion_id, border_station_id, export_station_id, import_station_id)
SELECT random()*39999+1, random()*39999+1,
CASE WHEN random()<0.1 THEN random()*39999+1 END,
CASE WHEN random()<0.1 THEN random()*39999+1 END,
CASE WHEN random()<0.1 THEN random()*39999+1 END
FROM generate_series(1,1000000) G(i);
CREATE TABLE hauls_fixed (
id serial PRIMARY KEY,
from_staion_id integer NOT NULL REFERENCES stations, -- станция отправления
to_staion_id integer NOT NULL REFERENCES stations, -- станция назначения
border_station_id integer NOT NULL REFERENCES stations, -- станция пересечения границы
export_station_id integer NOT NULL REFERENCES stations, -- станция экспортного досмотра
import_station_id integer NOT NULL REFERENCES stations -- станция импортного досмотра
);
INSERT INTO hauls_fixed (from_staion_id, to_staion_id, border_station_id, export_station_id, import_station_id)
SELECT from_staion_id, to_staion_id,
COALESCE(border_station_id,0), COALESCE(export_station_id,0),
COALESCE(import_station_id,0)
FROM hauls_nullable;
EXPLAIN ANALYZE
SELECT COALESCE(B.name,'-- отсутствует --'),
COALESCE(E.name,'-- отсутствует --'),
COALESCE(I.name,'-- отсутствует --')
FROM hauls_nullable H
LEFT JOIN stations B ON B.id=H.border_station_id
LEFT JOIN stations E ON E.id=H.export_station_id
LEFT JOIN stations I ON I.id=H.import_station_id;
Hash Left Join (cost=3993.07..27297.13 rows=1000000 width=96) (actual time=19.255..387.291 rows=1000000.00 loops=1)
Hash Cond: (h.import_station_id = i.id)
Buffers: shared hit=6722
-> Hash Left Join (cost=2662.05..23341.09 rows=1000000 width=14) (actual time=12.366..271.725 rows=1000000.00 loops=1)
Hash Cond: (h.export_station_id = e.id)
Buffers: shared hit=6291
-> Hash Left Join (cost=1331.02..19385.04 rows=1000000 width=13) (actual time=6.237..173.591 rows=1000000.00 loops=1)
Hash Cond: (h.border_station_id = b.id)
Buffers: shared hit=5860
-> Seq Scan on hauls_nullable h (cost=0.00..15429.00 rows=1000000 width=12) (actual time=0.010..40.307 rows=1000000.00 loops=1)
Buffers: shared hit=5429
-> Hash (cost=831.01..831.01 rows=40001 width=9) (actual time=6.181..6.182 rows=40001.00 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2227kB
Buffers: shared hit=431
-> Seq Scan on stations b (cost=0.00..831.01 rows=40001 width=9) (actual time=0.013..2.531 rows=40001.00 loops=1)
Buffers: shared hit=431
-> Hash (cost=831.01..831.01 rows=40001 width=9) (actual time=6.081..6.082 rows=40001.00 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2227kB
Buffers: shared hit=431
-> Seq Scan on stations e (cost=0.00..831.01 rows=40001 width=9) (actual time=0.009..2.539 rows=40001.00 loops=1)
Buffers: shared hit=431
-> Hash (cost=831.01..831.01 rows=40001 width=9) (actual time=6.839..6.840 rows=40001.00 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2227kB
Buffers: shared hit=431
-> Seq Scan on stations i (cost=0.00..831.01 rows=40001 width=9) (actual time=0.008..2.281 rows=40001.00 loops=1)
Buffers: shared hit=431
Planning:
Buffers: shared hit=18
Planning Time: 0.266 ms
Execution Time: 416.061 ms
EXPLAIN ANALYZE
SELECT B.name, E.name, I.name
FROM hauls_fixed H
JOIN stations B ON B.id=H.border_station_id
JOIN stations E ON E.id=H.export_station_id
JOIN stations I ON I.id=H.import_station_id;
Hash Join (cost=3993.07..28238.90 rows=1000000 width=15) (actual time=18.645..459.774 rows=1000000.00 loops=1)
Hash Cond: (h.import_station_id = i.id)
Buffers: shared hit=7663
-> Hash Join (cost=2662.05..24282.60 rows=1000000 width=14) (actual time=12.302..324.342 rows=1000000.00 loops=1)
Hash Cond: (h.export_station_id = e.id)
Buffers: shared hit=7232
-> Hash Join (cost=1331.02..20326.30 rows=1000000 width=13) (actual time=6.391..196.050 rows=1000000.00 loops=1)
Hash Cond: (h.border_station_id = b.id)
Buffers: shared hit=6801
-> Seq Scan on hauls_fixed h (cost=0.00..16370.00 rows=1000000 width=12) (actual time=0.009..39.691 rows=1000000.00 loops=1)
Buffers: shared hit=6370
-> Hash (cost=831.01..831.01 rows=40001 width=9) (actual time=6.336..6.337 rows=40001.00 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2227kB
Buffers: shared hit=431
-> Seq Scan on stations b (cost=0.00..831.01 rows=40001 width=9) (actual time=0.007..2.269 rows=40001.00 loops=1)
Buffers: shared hit=431
-> Hash (cost=831.01..831.01 rows=40001 width=9) (actual time=5.863..5.863 rows=40001.00 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2227kB
Buffers: shared hit=431
-> Seq Scan on stations e (cost=0.00..831.01 rows=40001 width=9) (actual time=0.012..2.315 rows=40001.00 loops=1)
Buffers: shared hit=431
-> Hash (cost=831.01..831.01 rows=40001 width=9) (actual time=6.298..6.299 rows=40001.00 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2227kB
Buffers: shared hit=431
-> Seq Scan on stations i (cost=0.00..831.01 rows=40001 width=9) (actual time=0.015..2.631 rows=40001.00 loops=1)
Buffers: shared hit=431
Planning:
Buffers: shared hit=18
Planning Time: 0.261 ms
Execution Time: 488.732 ms
Пример приближен к реальности, так как действительно 90% грузоперевозок выполняются внутри РФ. Если же посмотреть на форматы данных АСОУП-3 или ЭТРАН, то там 99% полей nullable (minOccurs=“0” в xsd) и по факту, например в ж/д накладной заполняются в среднем 5% полей. Что, в принципе, логично. Так как ссылки на договора и акты охраны указывается для 0.01% грузоотправок, ссылки на договора и акты сопровождения - 0.1%, есть множество полей, заполняемых только для некоторых видов грузов, локомотивов или видов вагонов и т.п. Привожу в качестве примера, так как xsd обмена с АСОУП-3 и ЭТРАН общедоступны.
Откуда пошли ERP-системы - вопрос интересный.
Потому что это самый простой вариант реальной и достаточно сложной структуры БД, доступ к которой есть у любого желающего. Вы можете предложить иной вариант доступной Вам и мне реальной enterprise БД?
Сколько бы было у вас OUTER JOIN если бы не NULL в FK?
Столько же. Ведь выборка из таблиц операций идет почти всегда от справочников по соответствующим индексам. Что логично, так как в обратном случае мог работать разве что индекс по датам.
Да, если идет агрегация данных, например “справочник с количеством ссылающихся операций” - тогда да, LEFT JOIN нужен. Но так ли много подобных запросов?
Почти в каждом отчете.
Найти искусственный пример,
Зачем искать? Так сложно самому написать скрипт примера?
Я спорю именно с “может приводить к увеличению таблицы в разы”
Какой смысл спорить, если я уже предложил решение этого спора? Называйте ERP и там увидим. Хоть SAP, хоть OEBS, хоть Dynamics.
А минимизация ошибок в запросах лично для меня в приоритете.
Из этого лишь следует, что у Вас крошечные объёмы данных. Иначе бы производительность была бы существенно важнее.
Так себе ответ. OUTER JOIN применяются не редко. Просто потому, в таблице операций может не быть ссылок на все элементы справочника, который в запросе фильтруется по каким-то полям. А отсутствие записей - это тоже результат.
Для примера, в одном из моих текущих проектов по логистике вообще нет nullable PK. При этом там INNER встречается 38 тысяч раз, а OUTER - 18 тысяч раз. То есть, каждый третий JOIN - OUTER.
как часто результаты агрегатных функций попадают в условия?
Да повсеместно. Хоть SUM по нулевому количеству записей или LEAD/LAG на первой или последней записи в PARTITION.
Я не думаю, что “таблица из восьми полей, все могут быть NULL” - очень частая история.
На основании чего такие мысли? Предлагаю взять любую ERP на Ваш выбор и я в ней укажу сходу десятки таких таблиц.
Но есть и выигрыш в производительности от фиксированного размера кортежа - не стоит про это забывать.
Впервые такое слышу. Вот от уменьшения размера кортежа, благодаря которому на одной странице умещается больше кортежей - выигрыш в производительности показать могу легко. Только до компа добраться надо. А сможете ли Вы показать тут повторяемый пример, доказывающий Ваше утверждение?
Кроме явных случаев с OUTER JOIN, NULL могут возвращать функции. В том числе и агрегатные.
Что касается размеров кортежа, то в PostgreSQL NULL занимает в кортеже один бит, integer - 32 бита, 0::decimal - 3+2 байта = 40 бит. То есть, если в кортеже из восьми integer полей семь NULL, то его общая длина будет 23+1+4=28 байт. А если все восемь ноль - то 23+1+4*8=56 байт. В случае пары десятков decimal или varchar - можете сами посчитать, учитывая, что NULL-mask требует по байту на каждые восемь nullable полей.
В некоторых случаях такой подход может приводить к увеличению таблицы в разы. К тому же он всё равно не решает проблемы, так как NULL в поле запроса может возникать не только из фактического значения поля в таблице.
Упущен важный момент. Немало людей, которым делать одно и то же, которое они уже умеют делать субъективно в совершенстве, просто надоедает и не хочется. Когнитивная нагрузка им просто необходима. Если таким людям не давать периодически задачи, которые требуют усиленной когнитивной нагрузки, они или выгорят, или уйдут.
Борьба может быть разной. Я уже приводил выше пример борьбы с трудноуловимой багой. Пока человек работает и что-то производит, пусть даже компьютерные игры или фильмы для развлечения соплеменников, ему будет с чем бороться.
Надо объяснять, почему ни фильм, ни современную компьютерную игру без иерархии управления создать невозможно?
И как из этого следует, что волки без стаи не вымерли бы? А то, что размер дичи, на которую охотятся волки и тигры одинаков, тогда как их размеры очень разные не смущает? А уж геноцид волков и геноцид тигров даже сравнивать странно. Что-то про массовые истребления тигров с вертолётов я не слышал.
Я бы начинал с того, что not manager_id=id тоже не инвертирование условия при наличии NULL. Хотя ошибку чаще допускают, ставя NOT перед скобками с более сложным логическим выражением.
Вы для начала представьте себе жизнь без иерархической организации, когда нет ни пожарных, ни скорой помощи, ни полиции. А потом уже сравнивайте с мышами )))
Для простоты понимания, волки без стаи уже давно бы вымерли.
А иерархическая организация с вожаками есть у всех приматов, включая человека.
Обвинять во лжи, не предъявляя доказательств - это называется клевета. А примера кода, который можно запустить и сравнить с вышеописанным решением хотя бы на тысяче сообщений, порождающих 100 тыс. записей, я что-то не увидел.
При этом проверить, что производительность Sink (даже с моей доработкой и оптимизацией) отличается от вышеприведенного решения почти на два порядка, совсем не сложно.
возвращаясь к человечеству, которое вот грызёт друг дружку как те мышки в опыте Кэлхуна. Я утверждаю, что если начать экспансию в космос, то это переведёт вектор агрессии с друг друга на среду.
Вы путаете причину и следствие. Повышение количества равноправных и независимых особей в ограниченном пространстве действительно приводит к повышению агрессии между ними. Внешняя опасность для группы особей приводит к необходимости создания иерархии управления, что существенно снижает как агрессию внутри этой группы, так и эту внешнюю опасность. Но из этого совершенно не следует, что иерархическая организация возникает только под влиянием внешней опасности.
при увеличении количества кошек - число конфликтов бы росло
Не факт. И среди кошек мог появиться лидер, так же как пёс, взявший на себя роль вожака, обеспечивающего безопасность в обмен на запрет любой агрессии как друг к другу, так и к себе.
Аналогично и у людей, и у собак, и у волков и т.п. Агрессия между членами стаи пресекается вожаком, который так же отвечает за безопасность и выживание стаи. А вот когда бардак и анархия, а не иерархическая организация - вот тогда и начинается агрессия.
Если руководство, в первую очередь финдир при согласовании с главбухом, приняли решения возложить некоторые операции необходимые для управленческого и финансового учёта на бухгалтера - будет делать, как миленький. Проверено неоднократно в McDonalds, P&G, Bunge, Siemens и многих других компаниях, где я так или иначе принимал участие во внедрении ERP.
Бухгалтерский учёт - лишь ничтожная часть планирования ресурсов предприятия. И то, что 1С уже очень давно (с 2013 года) пытается из бухгалтерии сделать ERP без кардинального пересмотра архитектуры - это их проблемы.
Вы вообще всё перепутали. Одна из основных причин прокрастинации - физиологическая. Перегруженность работой, усталость и недостаток сна заставляют экономить ресурсы. Остальные причины - перфекционизм, страх неудачи и скучная рутина, так же не имеют никакого отношения ни к зажиточности, ни к условному изобилию.
Вам виднее:
В том же "Граде обреченном" немало героев, которых заботило далеко не только еда, питьё и жильё. Так что плохой пример.
Вообще связи не вижу. При чем тут откладывание важных дел? Если человек вместо важной работы занимается любимым делом (музыкой, фотографией, спортом и т.п.) - он лишь перенаправляет свои усилия в другом направлении.
Вместо hash запрос был загнан в merge join, что и упростило логику (не потребовалось считать хеши) и ускорило выполнение.
Объясняю, очень сильно упрощая. Есть справочник вагонов:
Есть рейсы вагонов:
Задача - вывести для каждого вагона, доступного на текущую дату (между accure_date и dismiss_date) остаточный пробег до планового ремонта, как разницу между максимальным пробегом и пробегом во всех совершенных им рейсов с момента акта получения вагона. С учётом того, что в наличии есть вагоны, которые после покупки, взятия в аренду или получения их по доверенности ещё не совершали рейсов. И таких вагонов у крупных операторов ежедневно сотни.
Во-первых, сразу видим несоответствие между
и
Ну и, как следствие, у AI возникла галлюцинация и он вставил в таблицу metrics_nullable множество нулей, хотя их там быть не должно.
Для информации, у меня только одна таблица истории дислокаций вагонов больше двух терабайт. DWH же суммарно давно петабайт преодолел.
Во-вторых, добавлять сюда размер индексов некорректно, так как обсуждался размер кортежей.
Во-третьих, я писал "в некоторых случаях", из чего следует, что могу привести пример.
Пожалуйста
В-четвертых, проблема не столько в тупой выборке с суммированием, сколько в том, что NULL поле не требует поиска в индексе справочника, тогда как 0 - требует.
Поэтому имеем в результате
Пример приближен к реальности, так как действительно 90% грузоперевозок выполняются внутри РФ. Если же посмотреть на форматы данных АСОУП-3 или ЭТРАН, то там 99% полей nullable (minOccurs=“0” в xsd) и по факту, например в ж/д накладной заполняются в среднем 5% полей. Что, в принципе, логично. Так как ссылки на договора и акты охраны указывается для 0.01% грузоотправок, ссылки на договора и акты сопровождения - 0.1%, есть множество полей, заполняемых только для некоторых видов грузов, локомотивов или видов вагонов и т.п. Привожу в качестве примера, так как xsd обмена с АСОУП-3 и ЭТРАН общедоступны.
Потому что это самый простой вариант реальной и достаточно сложной структуры БД, доступ к которой есть у любого желающего. Вы можете предложить иной вариант доступной Вам и мне реальной enterprise БД?
Столько же. Ведь выборка из таблиц операций идет почти всегда от справочников по соответствующим индексам. Что логично, так как в обратном случае мог работать разве что индекс по датам.
Почти в каждом отчете.
Зачем искать? Так сложно самому написать скрипт примера?
Какой смысл спорить, если я уже предложил решение этого спора? Называйте ERP и там увидим. Хоть SAP, хоть OEBS, хоть Dynamics.
Из этого лишь следует, что у Вас крошечные объёмы данных. Иначе бы производительность была бы существенно важнее.
Так себе ответ. OUTER JOIN применяются не редко. Просто потому, в таблице операций может не быть ссылок на все элементы справочника, который в запросе фильтруется по каким-то полям. А отсутствие записей - это тоже результат.
Для примера, в одном из моих текущих проектов по логистике вообще нет nullable PK. При этом там INNER встречается 38 тысяч раз, а OUTER - 18 тысяч раз. То есть, каждый третий JOIN - OUTER.
Да повсеместно. Хоть SUM по нулевому количеству записей или LEAD/LAG на первой или последней записи в PARTITION.
На основании чего такие мысли? Предлагаю взять любую ERP на Ваш выбор и я в ней укажу сходу десятки таких таблиц.
Впервые такое слышу. Вот от уменьшения размера кортежа, благодаря которому на одной странице умещается больше кортежей - выигрыш в производительности показать могу легко. Только до компа добраться надо. А сможете ли Вы показать тут повторяемый пример, доказывающий Ваше утверждение?
Не применимы, так как значением NULL=a и NULL<>a будет не false или true, а NULL
Кроме явных случаев с OUTER JOIN, NULL могут возвращать функции. В том числе и агрегатные.
Что касается размеров кортежа, то в PostgreSQL NULL занимает в кортеже один бит, integer - 32 бита, 0::decimal - 3+2 байта = 40 бит. То есть, если в кортеже из восьми integer полей семь NULL, то его общая длина будет 23+1+4=28 байт. А если все восемь ноль - то 23+1+4*8=56 байт. В случае пары десятков decimal или varchar - можете сами посчитать, учитывая, что NULL-mask требует по байту на каждые восемь nullable полей.
В некоторых случаях такой подход может приводить к увеличению таблицы в разы. К тому же он всё равно не решает проблемы, так как NULL в поле запроса может возникать не только из фактического значения поля в таблице.
Упущен важный момент. Немало людей, которым делать одно и то же, которое они уже умеют делать субъективно в совершенстве, просто надоедает и не хочется. Когнитивная нагрузка им просто необходима. Если таким людям не давать периодически задачи, которые требуют усиленной когнитивной нагрузки, они или выгорят, или уйдут.
Потому что это мыши неприспособленные к иерархическому взаимодействию, как люди. Выше я приводил пример с собаками и волками.
Борьба может быть разной. Я уже приводил выше пример борьбы с трудноуловимой багой. Пока человек работает и что-то производит, пусть даже компьютерные игры или фильмы для развлечения соплеменников, ему будет с чем бороться.
Надо объяснять, почему ни фильм, ни современную компьютерную игру без иерархии управления создать невозможно?
И как из этого следует, что волки без стаи не вымерли бы? А то, что размер дичи, на которую охотятся волки и тигры одинаков, тогда как их размеры очень разные не смущает? А уж геноцид волков и геноцид тигров даже сравнивать странно. Что-то про массовые истребления тигров с вертолётов я не слышал.
Я бы начинал с того, что not manager_id=id тоже не инвертирование условия при наличии NULL. Хотя ошибку чаще допускают, ставя NOT перед скобками с более сложным логическим выражением.
Вы для начала представьте себе жизнь без иерархической организации, когда нет ни пожарных, ни скорой помощи, ни полиции. А потом уже сравнивайте с мышами )))
Для простоты понимания, волки без стаи уже давно бы вымерли.
А иерархическая организация с вожаками есть у всех приматов, включая человека.
Обвинять во лжи, не предъявляя доказательств - это называется клевета. А примера кода, который можно запустить и сравнить с вышеописанным решением хотя бы на тысяче сообщений, порождающих 100 тыс. записей, я что-то не увидел.
При этом проверить, что производительность Sink (даже с моей доработкой и оптимизацией) отличается от вышеприведенного решения почти на два порядка, совсем не сложно.
Вы путаете причину и следствие. Повышение количества равноправных и независимых особей в ограниченном пространстве действительно приводит к повышению агрессии между ними. Внешняя опасность для группы особей приводит к необходимости создания иерархии управления, что существенно снижает как агрессию внутри этой группы, так и эту внешнюю опасность. Но из этого совершенно не следует, что иерархическая организация возникает только под влиянием внешней опасности.
Не факт. И среди кошек мог появиться лидер, так же как пёс, взявший на себя роль вожака, обеспечивающего безопасность в обмен на запрет любой агрессии как друг к другу, так и к себе.
Аналогично и у людей, и у собак, и у волков и т.п. Агрессия между членами стаи пресекается вожаком, который так же отвечает за безопасность и выживание стаи. А вот когда бардак и анархия, а не иерархическая организация - вот тогда и начинается агрессия.