LINUX.ORG.RU
ФорумTalks

Вот вы ругаетесь «индусы», «индусы»...


0

0

Давайте я вам лучше про русских раскажу?

Итак, невъ...нно "корпоративная платформа". Оракел, репликация, оперативный, бухгалтерский, табельный и прочие учеты, ынытрпрайз, все понты. Самописное _всё_

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

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

Но нет - это не ынтырпрайс. Поэтому делается "почти-копия" центрального сервера со всей его невъ...ной базой, и ставится на комп этого самого удаленного объекта(!). Причем структура баз уже ОТЛИЧАЕТСЯ. Вплоть до различия в длине полей (фак!). Соответственно вместо компактной надежной, в которой из движущихся частей только винт и вентилятор блока питания, водружается сервер об двухъядерном процессоре и двух гигах оперативки, с ораклом 10g. На него ставится ДВЕ версии оракла - 10.2 и 8.0.5(!!!!), и клиентское приложение, написанное на... в общем не важно на чем. Достаточно точной альтернативой будет "на MS Access".

Не буду вдаваться в детали этого приложения, скажу только "программу страшнее я видел только трижды", а я, среди прочего, являюсь преподавателем в университете, то есть регулярно вижу студенческие "курсовые", "семестровые" и "дипломные" работы - то есть можете представить ЧТО это такое.

Итак, продолжаем банкет. Настройки винды (сервер на винде, да-да), оракла (noarchivelog), файрвола (отключен) оставим в стороне, заглянем под крышку этмоу чуду.

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

Ну и само собой, еще множество справочников имеет аналогичную структуру (ну например погрузочно-разгрузочные терминалы - есть таблица терминалов под каждый тип: водный, ЖД, автомобильный... и есть сводная таблица "вес терминалы" куда триггеры подкладывают копии записей). Ах да - не все документы ссылаются на сводную таблицу. Некоторые ссылаюстя на таблицу объектов конкретного типа.

Продолжаем банкет, исследуем базу. Находим таблицу "свойства товара", в которую можно записать всякие дополнительную информацию (ну например страна-производитель, цвет, размер - в общем что угодно). Организовано красиво - есть таблица свойств, есть таблица значений свойств - ссылка на товар, ссылка на свойство, значение свойства (строка) и дата начала действия данного значения свойства. Даты окончания действия этого значения тупо НЕТ. Rак в этой ситуации можно написать номральный запрос "по состоянию на конкретную дату"?!?! ХЗ. Ладно, хрен с вами. Переживем.

Начинаем работу, вводим товар, штрих-код (это такое свойство есть)... Что-то не то. То товар по штрих-коду не находится, то ошибка выскакивает, то еще что-то. На центральном сервере товар появляется, на серверах "на местах" - появляется но штри-код не вводится. Мля. Начинаем ковырять триггеры: оказывается, если кто-то пытается ввести занчение "штрих-код" для товара, то один из триггеров выкидывает такой фортель: если код (ID) свойства равен 10 то автоматически добавляется строка в специальную таблицу штрих-кодов! Причем этих триггеров существует два варианта - один на центральном сервере, другой на сервере точки продаж, причем дублирование штрих-кодов на центральном сервере возможно, а на сервере точки продаж на это специальной таблице стоит проверка на уникальность штрих-кода! На этом месте у меня начинается истерика, поскольку пользователи вводят товары на центральном сервере, где можно в результате получить дублирующиеся штрих-коды. И мы их получили. Обращаемся к разработчикам - они отказываются включать проверку на дублирование штрих-кода в базе центрального сервера. Проблема дублей их не волнует. Хрен с ними, пишу код сам, не трогая "аффтарские" чудачества.

В один день перестает работать репликация (точнее, она два раза в неделю ломается, но не будем заострять внимание). Результат разборок ужасает. Процесс репликации оказывается происходит так: каждое изменение, которое должно быть отреплицировано, записывается в специальную таблицу.

Потом с помощью ораклового exp данные этой таблицы выгружаются в дамп (бинарник) и этот дамп отправляется к местоназначению. На той стороне с помощью IMP данные вливаются в базу и потом специальная программка формирует SQL-запросы, которые накатывает в базу. Причем термина "порядок репликации" (типа сначала реплицируем справочники, потом документы которые на них ссылаются) нет. Программа тупо делает три попытки, и если обломалась - репликация помечается как "ошибочная".

В экзешник программы репликации зашиты имя и пароль юзера, под которыми она подключается к базе(!!!) Эта программа формирует и выполняет SQL-запросы по алгоритму

$sql = "insert into tablename(field1,field2) values ('" + $value1 + "','" + $value2 + "')";

exec_sql( $sql );

И что происходит если $value1 является строкой, содержащей апостроф?

Вот так вот бывает. А вы говорите "индусы", "быдлокодеры"...

★★★★★
Ответ на: комментарий от gdv2

> Как Ваш запрос поведет себя в этой ситуации?

Для начала я предлагаю вам написать запрос "вывести цены всех товаров по состоянию на 4 аперля 2008 года". Реляционный. С вменяемым временым выполнения.

Кроме того, сам факт того что "это свойство отсутствуие в указанный интервал" является абсолютно корректным условием.

Например, сертификат на продукцию имеет срок действия. И следующий сертификат может действительно начинать действовать не сразу после окончания действия старого, а в случае с "только датой начала" у вас нет возможности создать интервал отстутствия

no-dashi ★★★★★
() автор топика
Ответ на: комментарий от vada

>>учите английский

>А нахрена? Я Си знаю. В английском все слова от туда.

+1 =)))))))))))))))))

cavia_porcellus ★★★★
()

да все мы знаем, что дельфинисты и ораклисты тупоголовые бараны, которые на каждый клиентский компютер крякнутый ыракл ставят. Стрелять гадов таких надо.

anonymous
()
Ответ на: комментарий от anonymous

> на каждый клиентский компютер крякнутый ыракл ставят

Кстати да, с установкой по два инстанса оракла на клиента - лиценный оракел, наверное, обошёлся бы дороговато.

anonymous
()
Ответ на: комментарий от anonymous

Лучше просто обобщить до "российские программисты".

anonymous
()
Ответ на: комментарий от no-dashi

> Для начала я предлагаю вам написать запрос "вывести цены всех товаров по состоянию на 4 аперля 2008 года". Реляционный. С вменяемым временым выполнения.

select avg(price_value) from price where price_product_id=:pid and price_valid_from in ( select max(price_valid_from) from price where price_product_id=:pid and price_valid_from<=:date )

Теперь расскажи нам, что это будет работать "долго". И что такое "долго". :-)

anonymous
()
Ответ на: комментарий от no-dashi

> Для начала я предлагаю вам написать запрос "вывести цены всех товаров по состоянию на 4 аперля 2008 года". Реляционный. С вменяемым временым выполнения.

gdv=> \d prod
               Table "test.prod"
  Column   |         Type          | Modifiers 
-----------+-----------------------+-----------
 prod_id   | integer               | not null
 prod_name | character varying(64) | 
Indexes:
    "prod_pk" UNIQUE, btree (prod_id)

gdv=> \d param
                  Table "test.param"
   Column   |            Type             | Modifiers 
------------+-----------------------------+-----------
 prod_id    | integer                     | not null
 param_id   | integer                     | not null
 date_start | timestamp without time zone | not null
 value      | numeric(18,2)               | 
Indexes:
    "param_pk" UNIQUE, btree (param_id, prod_id, date_start)

gdv=> select count(*) from prod;
 count 
-------
   999
(1 row)

gdv=> select count(*) from param;
 count  
--------
 440559
(1 row)

Time: 127.030 ms

gdv=> \o /dev/null
gdv=> select P.prod_id,P.prod_name,V.value
from prod P
  join param V on (V.prod_id=P.prod_id)
  join (select prod_id,max(date_start) as date_start
from param where param_id=2 and date_start<'2007-01-30'
group by prod_id) S on (S.prod_id=P.prod_id and V.date_start=S.date_start)
where V.param_id=2;
Time: 54.205 ms

gdv=> explain select P.prod_id,P.prod_name,V.value
from prod P
  join param V on (V.prod_id=P.prod_id)
  join (select prod_id,max(date_start) as date_start
from param where param_id=2 and date_start<'2007-01-30'
group by prod_id) S on (S.prod_id=P.prod_id and V.date_start=S.date_start)
where V.param_id=2;
                                                          QUERY PLAN                                                          
-------------------------------------------------------------------------------
-----------------------------------------------
 Hash Join  (cost=6206.46..6747.13 rows=49 width=161)
   Hash Cond: (v.prod_id = p.prod_id)
   ->  Nested Loop  (cost=6186.56..6726.83 rows=49 width=19)
         ->  HashAggregate  (cost=6186.56..6187.36 rows=64 width=12)
               ->  Bitmap Heap Scan on param  (cost=1926.32..6044.50 rows=28412 width=12)
                     Recheck Cond: ((param_id = 2) AND (date_start < '2007-01-30 00:00:00'::timestamp without time zone))
                     ->  Bitmap Index Scan on param_pk  (cost=0.00..1919.22 rows=28412 width=0)
                           Index Cond: ((param_id = 2) AND (date_start < '2007-01-30 00:00:00'::timestamp without time zone))
         ->  Index Scan using param_pk on param v  (cost=0.00..8.40 rows=1 width=23)
               Index Cond: ((v.param_id = 2) AND (s.prod_id = v.prod_id) AND (v.date_start = s.date_start))
   ->  Hash  (cost=14.40..14.40 rows=440 width=150)
         ->  Seq Scan on prod p  (cost=0.00..14.40 rows=440 width=150)
(12 rows)

Time: 1.239 ms

gdv2
()
Ответ на: комментарий от gdv2

Тогда затащи ид и дату в первичный ключ. Будем надеяться, что у топикстартера не хранится по несколько цен на один и тот же продукт на одном и том же интервале времени.

anonymous
()
Ответ на: комментарий от anonymous

> Теперь расскажи нам, что это будет работать "долго"

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

no-dashi ★★★★★
() автор топика
Ответ на: комментарий от no-dashi

Просто если у тебя в одном запросе встречаются записи с разными ценами и из разных периодов (а это постоянно так бывает), то проще убиться, или пойти писать функцию. Вот только create procedure (чтобы функцию написать) тебе никто не дал... Хаха.

no-dashi ★★★★★
() автор топика
Ответ на: комментарий от UserUnknown

Однако я вот что подумал: раскладку переключать не надо при наборе русского текста, мелочь - а приятно.

AndreyKl ★★★★★
()

А что, в Ъ тырпрайзе по другому как-то бывает? Там по другому-то и быть не может, по вполне очевидным причинам.

bugmaker ★★★★☆
()

no-dashi, уважаемый ... я могу привести лиш частичный список подпадающий под ваше описание :) не идентично, но оччень похоже :)

1) АСТОР ВЦ - Торговый Дом

2) Новая Афина - АБС "Новая Афина"

Ну и под занавес, практически ВСЁ по производимое по федеральным заказам, такое впечатление что его (ПО) пишут не программисты а какие-то дети индиго с ГСМ вместо мозга.

robot12 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.