LINUX.ORG.RU

Стоит ли использовать MongoDB для финансовых приложений и почему?

 


0

2

Углубляюсь в изучение этой БД. Пока что везде трындят что для финансовых данных лучше использовать реляционные БД, мол нереляционные не настолько стабильны. Но учитывая последние версии монги - проблемы с сохранностью данных уже ушли в прошлое.

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

★★★★★

Последнее исправление: Siado (всего исправлений: 1)
Ответ на: комментарий от zz

IT директор сокрее застрелится чем пустит что-то кроме sql в биллинг

vromanov ★★★
()
Ответ на: комментарий от AlexM

Или поле «регистратор» у движения по взаиморасчётам.

Вообще, весь этот ужас, как Вы говорите, отлично скрывается нормальным Data Abstraction Layer,

На есть ли проще вариант запроса человек как раз и мучает SQL по этому поводу.

Типовая ситуация: у проводки есть поле регистратор. Видов регистраторов 500 разных. Из них у 300 есть поле Контрагент. Надо получить отчёт типа «описание проводки, сумма, контрагент». В mongo это будет запрос по двум таблицам (документы + проводки), в SQL — будет join на 300 таблиц или в таблицу документов придётся заносить все поля, которые есть хотя бы в одном виде документов.

И Вам совершенно не важно, как эти данные хранятся «в подложке».

Тогда вообще вопрос выбора СУБД неважен. Если скорость не важна, так ACID можно и принудительной сериализацией получить (блокируя всю БД на запрос). Или вообще, зачем СУБД? Прикрутил Object Prevalence, побольше swap-а и вперёд.

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

В mongo это будет запрос по двум таблицам

А что мешает хранить необходимые движения в теле документа? Аналитика усложнится — да, в случае изменения движений документ придется переписывать. С индексами будет сложновато... Но все решаемо.

По идее, весь учет как минимум раз в месяц должен закрываться. Иначе, это не учет, а бардак.

Кстати говоря, не понимаю желания хранить документы в нормализованном виде в SQL базах. Откуда вообще эта хрень пошла?

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

А что мешает хранить необходимые движения в теле документа? Аналитика усложнится — да, в случае изменения движений документ придется переписывать. С индексами будет сложновато... Но все решаемо.

В современных СУБД можно хранить странные структуры в XML и даже строить индексы по полям этого XML.

Кстати говоря, не понимаю желания хранить документы в нормализованном виде в SQL базах. Откуда вообще эта хрень пошла?

Видимо от желания делать фильтрацию, сортировку по полям документов.

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

Есть же какие-то общие поля? В PostgreSQL есть наследование таблиц. Делаем таблицу «контрагентов», от нее наследуем таблицы «физлица» и «юрлица», никаких огородов

http://www.postgresql.org/docs/9.3/static/ddl-inherit.html

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

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

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

Что такое «потомок контрагента»? Таблица, которая наследуется от контрагента? Там же в ссылке все написано. Контрагенты - это все: собственно контрагенты, физлица, юрлица и прочие потомки. Наоборот, для того чтоб делать запросы только к контрагентам (родителю) нужно указывать ключевое слово ONLY.

anonymous
()

обязательно @ ни в коем случае

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

Там же в ссылке все написано. Контрагенты - это все: собственно контрагенты, физлица, юрлица и прочие потомки.

По ссылке не очень понятно. Можно сделать запрос

SELECT name, altitude
    FROM cities
    WHERE state = 'NY';
?

Если нет, то толку мало (в mongo так можно)

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

А что в Монге возвращает этот запрос? В примере есть таблица городов, в ней нет штатов. От нее наследуется таблица столиц, в ней есть штат. Выборка со штатом имеет смысл только для столиц.

Возможно, пример какой-то не очень удачный, сбивает с толку, но это обычное наследование - берем базовую таблицу, к ней добавляем еще поля. Запросы к базовой таблице, очевидно, не могут использовать поля из таблиц-потомков

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

У меня есть проводка. У неё есть поле контрагент. Я в одну проводку хочу записать айди физлица, в другую - юрлица. Я это могу делать, только если не буду делать foreign key constraint (теряя гарантии БД).

Хотя в принципе наверное как то будет работать, джойны по идее будут работать, просто ручками придётся всё проверять.

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

У меня есть проводка. У неё есть поле контрагент. Я в одну проводку хочу записать айди физлица, в другую - юрлица. Я это могу делать, только если не буду делать foreign key constraint (теряя гарантии БД).

У тебя будет целостность внешних ключей по полю контрагент. Там не сможет появиться контрагент, которого нет в таблице контрагентов. Если тебе нужны еще какие-то ограничения, можно их задать в constraints:

http://www.postgresql.org/docs/9.3/static/ddl-constraints.html

Или в триггере на вставку/обновление (before insert/update)

http://www.postgresql.org/docs/9.3/static/sql-createtrigger.html

Или в правилах

http://www.postgresql.org/docs/9.3/static/sql-createrule.html

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

У тебя будет целостность внешних ключей по полю контрагент. Там не сможет появиться контрагент, которого нет в таблице контрагентов. Если тебе нужны еще какие-то ограничения, можно их задать в constraints:

У меня вообще нет никаких записей в таблице контрагентов, это глупо. Это абстрактный тип. Все записи или в физлицах или в юрлицах.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner
create table partners -- контрагенты
(
        id serial primary key,
        name text
);

create table npersons -- физлица
(
        x integer not null
) inherits (partners);

create table legalents -- юрлица
(
        y integer not null
) inherits (partners);

-- возвращаем true только если partnerid не в базовой таблице
create or replace function check_partnerid(partnerid integer) returns boolean as
$$
 SELECT
        CASE count(id)
                WHEN 0 THEN false
                ELSE true
        END from partners, pg_class p where partners.id=$1 and partners.tableoid = p.oid and p.relname<>'partners'                 
$$ language 'sql';

create table docs (
 partnerid integer
 -- табличное ограничение целостности
 CONSTRAINT pcheck check (check_partnerid(partnerid))
);

При вставке в docs значение с некорректным partnerid будет ошибка: «новая строка в отношении „docs“ нарушает ограничение-проверку „pcheck“»

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

Заметил только сейчас, подумаю и предметно отвечу чуть позже.

AlexM ★★★★★
()
Ответ на: комментарий от monk

человек как раз и мучает SQL по этому поводу.

Ну, вроде бы, уже домучал, судя по всему.

Типовая ситуация: у проводки есть поле регистратор. Видов регистраторов 500 разных. Из них у 300 есть поле Контрагент.

А тут, на самом деле, нужно смотреть на задачу целиком, и, возможно, потом, при изменении условий существования, время от времени к этому вопросу возвращаться.

Я не являюсь сколько-нибудь «настоящим ДБА», в нашей Компании это можно себе позволить :) Но даже у меня, знакомого только с самыми базовыми, грубо говоря, правилами общения с РСУБД, вырисовываются следующие альтернативные пути решения данной задачи:

1. Да, брать и джойнить таблицы во множестве. С нормальным DSL'ем, строящим SQL'ем (у нас в Компании - нормальный, хотя по сравнению с новомодными штуками, и несколько старомодный) это проблем не вызывает, наворотить кода, который потом будет преобразован в сиквель на полторы-две страницы убористого текста - никаких проблем.

Естественно, при этом надо смотреть, чтобы результирующий сиквель не содержал никаких безумств и нормально ложился на целевую базу и её индексы. Но само по себе построение и последующее поддержание в актуальном состоянии на протяжении всей эволюции базы и её схемы, в общем, проблем не вызывает.

Естественно, что «практика - критерий истины», и в какой-то момент это решение может стать неприемлемым по тем или иным причинам, это не страшно.

2. Выделить для регистратора общую часть (таблицу), стащить туда все поля, более-менее похожие на общие (поле Контрагент, по первым признакам, похоже на таковое) и дальше работать «как с базовым классом и наследниками». Там, где контрагентов нет - ну, будут NULL'ы, они недорого стóят в нормальных базах. Можно при этом навесить констрэйнты так, чтобы при занесении/обновлении данных проверялось, указан ли контрагент для тех типов регистраторов, где он необходим.

3. Разумная комбинация подходов 1 и 2.

4. Специфичные для БД реализации решения 2, например, в постгресе можно поглядеть на наследование таблиц. Насколько я понимаю, внутри там всё та же неонка, но выглядящая приятно для глаз.

При этом наверняка «сертифицированные ДБА» смогут подсказать и более оптимальное для случая каждой конкретной базы решение. Ну, с другой стороны, не зря ж они свой хлеб с икрой едят.

Тогда вообще вопрос выбора СУБД неважен. Если скорость не важна,

Э-э-э, не. Про «скорость не важна» я не говорил ни слова ни полслова. Чаще всего, скорость не менее важна, чем надёжность базы и консистентность данных в ней.

Здесь-то и задача основная заключается в том, чтобы внимательно проанализировать предметную область и решаемые на данном этапе задачи, выделить из множества сущностей, их отношений и выполняемых над ними операций те «базовые кубики», из которых можно в дальнейшем «собирать» решения для задач в данной области, и для этих кубиков написать такой уровень абстракции, который, с одной стороны, будет обеспечивать достаточно оптимальный доступ к данным, а с другой - скрывать всю «кухонную грязь» от глаз прикладного программиста. Эдакий domain specific API, причём, замечу, не обязательно «объектно-ориентированный».

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

Я понимаю, что это всё звучит довольно абстрактно, «по-менеджерски» но и практические примеры такого многослойного подхода мне встречались. Но здесь, ключевым моментом является то, что DAL по природе своей специфичен для предметной области, это не типичное «а давайте одна строчка в таблице у нас будет представлена одним объектом». Ну и, конечно, то, что по мере эволюции проекта эволюционирует и DAL.

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

А что в Монге возвращает этот запрос?

Естественно, столицу штата Нью-Йорк.

А ещё там можно делать наподобие (с точностью до синтаксиса)

SELECT name, altitude
    FROM cities
    WHERE state IS NULL; 
и получать список всех городов кроме столиц.

Запросы к базовой таблице, очевидно, не могут использовать поля из таблиц-потомков

Вот это и плохо. Возьмем мой пример

CREATE TABLE document (
    number            text,
    date      date
);

CREATE TABLE invoice (
    client text
    sum float) 
INHERITS (document);

CREATE TABLE retail (
    sum float
) INHERITS (document);
...

И надо мне получить все документы по контрагенту. На обычном SQL мне придётся тщательно выписать UNION всего, где есть нужное поле.

На mongo всё гораздо проще.

P.S. Может есть открытая реализация SQL от 1C? Где можно писать запросы типа:

SELECT reg.client, reg.sum FROM
sum
WHERE
sum.client IN HIERARCHY (&Buyers)
AND reg.storage.type IN (1, 2, 10)

такое однозначно можно скомпилировать в SQL-92, но размер запроса сокращается в разы и писать проще.

И мой пример в нём будет тупо

SELECT document.number, document.date FROM
document
WHERE client = &client
при таблицах, описанных как выше по тексту (то есть client — поле возможных наследников).

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от AlexM

Да, брать и джойнить таблицы во множестве.

У MS SQL было ограничение на 256 таблиц в одном запросе. В PostgreSQL с этим как?

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

И надо мне получить все документы по контрагенту. На обычном SQL мне придётся тщательно выписать UNION всего, где есть нужное поле.

То есть из 100500 таблиц, которые объединены каким-то признаком (скажем, находятся в одной схеме или наследуются от одной таблицы, или начинаются с t_) нужно выбрать поля с одинаковым названием? Такое можно сделать выборками из системного каталога:

http://www.postgresql.org/docs/9.3/static/catalogs.html

Идем в этот каталог, отбираем таблицы по признаку и отбираем поля в этих таблицах.

Лень писать код, навскидку (после написания функции buyers) запрос будет выглядеть как-то так:

select * from buyers('sum');

Но придется что-то делать если поля 'sum' в разных таблицах будут разных типов. А как Монга себя при этом ведет? Приводит к одному типу?

Может есть открытая реализация SQL от 1C?

Да, PostgreSQL c патчами. Но там вроде бы патчи больше для того чтоб сгладить отличия PostgreSQL и MSSQL.

Ой, анонимусом это я и писал, лень было логиниццо.

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

Может есть открытая реализация SQL от 1C?

Да, PostgreSQL c патчами.

Я имел в виду компилятор SQL. Штуку в которую можно написать

SELECT reg.client, reg.sum FROM
reg
WHERE
reg.client IN HIERARCHY (&Buyers)
AND reg.storage.type IN (1, 2, 10)

А она в ответ выплюнет

SELECT reg.client, reg.sum FROM
reg 
LEFT JOIN clients ON reg.client = clients.id
LEFT JOIN clients2 ON client.parent = clients2.id
LEFT JOIN clients3 ON client2.parent = clients3.id
LEFT JOIN clients4 ON client3.parent = clients4.id
LEFT JOIN clients5 ON client4.parent = clients5.id
LEFT JOIN storage ON reg.storage = storage.id
WHERE
(clients.parent = &Buyers 
OR client2.parent = &Buyers
OR client3.parent = &Buyers
OR client4.parent = &Buyers
OR client5.parent = &Buyers)
AND storage.type = 1 OR storage.type = 2  OR storage.type = 10
На основании foreign key и т.д.

P.S. «IN HIERARCHY» реализовал неоптимально, так как оптимально сильно много писать.

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

Стэковерфлоу говорит, что жесткого предела нет. Но, разумеется, на такие случаи мы стараемся не наступать :-)

AlexM ★★★★★
()
Ответ на: комментарий от monk

Я имел в виду компилятор SQL

Не слышал. Может и выпустили. Но вообще что-то похожее можно набыдлокодить на pl/sql, не? Разве что синтаксис будет немного другой.

Я, кстати, подумал и все-таки написал функцию, которая пробегает по всем таблицам с каким-то критерием (table_name like 't%'), ищет заданное поле и выдает его значение. Принудительно приводит к типу text (на всякий случай). Можно не делать выборки из системного каталога, а ограничиться Information Schema:

http://www.postgresql.org/docs/9.3/static/information-schema.html

Так получается проще.

create or replace function buyers(fld text) returns setof text as
$$
declare
    t record;
    r record;
begin
  for t in select distinct table_name  from information_schema.columns  where table_schema = 'public' and column_name=fld  and table_name like 't%'
  loop
   for r in execute 'select ' || fld || '::text as rfld from ' || t.table_name
   loop
    return next r.rfld;
   end loop;
  end loop;
  return;
end;
$$ language 'plpgsql';

Использование:

$ select * from buyers('sum');
 buyers 
--------
 1
 2
...

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

Я, кстати, подумал и все-таки написал функцию, которая пробегает по всем таблицам

Это-то понятно. Я же написал выше, что вопрос mongo/sql только в скорости и удобстве. Если с удобством ещё можно что-то сделать (по примеру 1С или наклепав на PL/SQL всё что надо), то не думаю, что скорость функции, которая выполняет по запросу на таблицу через execute будет выше, чем один проход по таблице mongo.

Хотя да, рассуждения спекулятивные. На самом деле надо тестировать.

monk ★★★★★
()

Идиотов тред

MongoDB
финансовых

/0

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