Я тут уже писал. Рано уходить от SQL. Появились NewSQL решения, скоростные что черти. Я лично в восторге от MemSQL, я такого драйва на сотнях миллионах записей еще не видел. Хотя по их блогам там и милиарды за доли секунды процесаются, естественно в разумных рамках и с кучей нод.
Вам даже не надо TimeSeries базу искать, оно там автоматом! работает на том же SQL.
Я как-то ошибся в джоинах и получилось 80 миллионов на 80 миллионов cartesian exposion ( сколько там нулей будет ). Он это скушал за 3 минуты на двух 16-ти ядерных машинах. А я то думал чего это он начал так медленно это исполнять, а он стойко такую массу операций провел и сгрупировал, что и не укладывается в голове.
Пожалуй пока делать не буду. Разве что мне приспичит, а для начала хватит рекусивной CTE, которые поддерживаются.
Помнится у меня были проблемы с fetch/include + paging + order одновременно. И в nhibernate (и с linq и с query over) и в ef. В ef вообще include дико медленный, больше условно 5 штук ужасно тормозит само построение запроса.
Но я планирую все это пересмотреть и закончить это раз и навсегда.
Если есть замечания или предложения пожалуйста коментируйте этот issue https://github.com/linq2db/linq2db/issues/2452
Какие там в функции в Oracle… Невозможно за всем уследить.
Что задеть предлагаете? Я то слежу за EF Core репозиторием, только не использую. Вот и могу много болячек не рассмотреть. Если есть идеи, будет полезно узнать.
Видать не писатели. Нам бы документацию добить, а основная работа и библиотека высасывает оставшееся время.
Библиотека настолько усыпана фичами, что я уже и сам не знаю с чего начинать. Будет весьма сумбурно.
Не заумно ли тут все написано? Хотя, ту да голый SQL или поздно и я не уловил сути.
Я делал подобный финт ушами на linq2db (C#), как-то обходился без CTE и UNION по ненадобности.
Главное правило, все что в ORDER BY дожно быть уникальным ключем и тогда такой пейджинг делается с пол пинка. Где-то у меня валялся алгоритм который любой LINQ запрос заворачивал в такой пейджинг. По заявкам откопаю.
Принцип простой, есть ORDER BY asc1, asc2, desc1 DESC
asc1 + asc2 + desc1 — обязательно уникальный ключ
Первый запуск
SELECT * FROM table t
ORDER BY t.asc1, t.asc2, t.desc1 DESC
LIMIT 101
Берем на одну запись больше запоминаем asc1, asc2, desc1 последней записи. Также в таком варианте мы уже можем знать что страница последняя, на клиент возвращаем на одну запись меньше.
Второй запуск, следующая страница
SELECT * FROM table t
WHERE t.asc1 >= asc1 AND t.asc2 >= asc2 AND t.desc1 <= desc1
ORDER BY t.asc1, t.asc2, t.desc1 DESC
LIMIT 101
Повторяем запоминание попоследнаей записи.
Конечно алгоритм чуток больше еще учитывал, просто передал кратко принцип
нет. SQL тем и ценен, что он близок к человеческому языку, можно пару лет не прикасаться и не заглядывая в справочники написать запрос.
Это пока вам не придется писать оконные функции, Merge.
Ну в общем, ваше дело, а я прекрасно читаю LINQ и не хочу тратить время на написание SQL, склейку строк, нюансы синтаксиса. Рефакторить LINQ одно удовольствие, а вот SQL — тут без ста грам DataGrip, еще тот квест.
Вот пример, где кастомное решение рвет чистый SQL как тузик грелку:
Есть 1000 записей вида (int Id1, int Id2) в памяти приложения. Нужно выбрать из таблицы TableX все записи у которых совпадают эти два поля.
Вот решение с использованием ORM, удачи в написании SQL:
var items = // список элементов
using var tempTable = db.CreateTampTable("#Items", items);
// записи влетают в базу за секунду
var query =
from x in db.GetTable<TableX>()
from t in tempTable.InnerJoin(t => t.Id1 == x.tId1 && t.Id2 == x.Id2)
select x;
А что делает MERGE?
А какой SQL код получается в итоге?
Была бы база я бы выложил. MREGE синтаксис можно почитать в документации
П.С. безотносительно всего: мне читается такой код ооочень тяжело…
Это с непривычки, нужно понимать что SELECT всегда в конце — иначе типы не вывести. Ну и синтаксис современного C#, не знаю как у вас с ним.
Если присмотритесть я почти не делал JOIN — все сделает библиотека через ассоциации между таблицами, их еще называют навигациями по свойствам.
Также я один раз задал фильтр по docId и больше этим не страдаю. Так уменьшается количество возможных багов (условие по JOIN неправильное, забыли фильтр наложить). Декомпозиция запросов в полный рост — то чего не хватает SQL.
Запчасти запросов я разложил по переменым, хотя можно было в некоторых местах и не делать этого. Все для того чтобы спокойно можно было каждый запрос проверить в дебаге.
К чему я веду — если иметь првильный тул, действительно можно обойтись без хранимок с минимумом оверхеда и максимальным mainteinability.
P.S.
Кстати, данный код будет работать на всех базах поддерживающих MERGE. Бибилиотека за вас учтет особенности синтаксиса нужной базы данных.
Так, для сравнения миров. Написано на C# с использованием linq2db. Все типобезопасно, те же три запроса только вставку переписал через MERGE и добавил тразакцию. Я бы с удовольствием посмотрел на код написанный спомощью JOOQ
void CloseDoc(IDataContext db, int docId, short type)
{
using var tran = db.BeginTransaction();
var documentQuery = db.GetTable<Document>().Where(d => d.id == docId);
var validationQuery = documentQuery
.Where(d => d.doc_type_id.In(6, 8) && d.DocPosition.kol ?? 0 != 0);
if (validationQuery.Any())
throw new Exception("Документы данного типа нельзя закрывать если есть позиции с не нулевыми количествами.");
var sourceQuery = from d in documentQuery
where d.DocType.credit_type.In(1, -1)
select new CurrentStock
{
mat_id = d.DocPosition.mat_id,
org_id = d.org_id_addr,
org_id_ur = d.org_id_ur,
kol = - (d.DocPosition.kol ?? 0) * d.DocType.credit_type * type,
reserve = - (d.DocPosition.kol ?? 0) * (d.DocType.credit_type == 1 ? 1 : 0) * type
};
db.GetTable<CurrentStock>()
.Merge()
.Using(sourceQuery)
.OnTargetKey()
.InsertWhenNotMatched()
.UpdateWhenMatched((t, s) => new CurrentStock
{
kol = t.kol + s.kol,
reserve = t.reserve + s.reserve
})
.Merge();
var deleteQuery =
from cs in db.GetTable<CurrentStock>()
from d in documentQuery.InnerJoin(d => cs.mat_id == dp.mat_id && cs.org_id == d.org_id_addr && cs.org_id_ur == d.org_id_ur)
where cs.kol == 0 && cs.reserve == 0
select cs;
deleteQuery.Delete();
tran.Commit();
}
Спасибо вам за DataGrip, я чесно давно не стыкался с тем что меня что-то не устаивает. По-моему вы движетесь в правильном направлении, все как програмисты любят — до мелочей.
Я тут уже писал. Рано уходить от SQL. Появились NewSQL решения, скоростные что черти. Я лично в восторге от MemSQL, я такого драйва на сотнях миллионах записей еще не видел. Хотя по их блогам там и милиарды за доли секунды процесаются, естественно в разумных рамках и с кучей нод.
https://www.memsql.com/blog/memsql-processing-shatters-trillion-rows-per-second-barrier/
Вам даже не надо TimeSeries базу искать, оно там автоматом! работает на том же SQL.
Я как-то ошибся в джоинах и получилось 80 миллионов на 80 миллионов cartesian exposion ( сколько там нулей будет ). Он это скушал за 3 минуты на двух 16-ти ядерных машинах. А я то думал чего это он начал так медленно это исполнять, а он стойко такую массу операций провел и сгрупировал, что и не укладывается в голове.
Пожалуй пока делать не буду. Разве что мне приспичит, а для начала хватит рекусивной CTE, которые поддерживаются.
Эти детские болезни полечены
SqlServer хинты есть
Но я планирую все это пересмотреть и закончить это раз и навсегда.
Если есть замечания или предложения пожалуйста коментируйте этот issue https://github.com/linq2db/linq2db/issues/2452
Какие там в функции в Oracle… Невозможно за всем уследить.
Черт, не заметил как вы пропустили https://github.com/linq2db/linq2db.EntityFrameworkCore
Те же
яйцафичи, только по правильному.Я подумаю, только это не так сразу.
Что задеть предлагаете? Я то слежу за EF Core репозиторием, только не использую. Вот и могу много болячек не рассмотреть. Если есть идеи, будет полезно узнать.
Видать не писатели. Нам бы документацию добить, а основная работа и библиотека высасывает оставшееся время.
Библиотека настолько усыпана фичами, что я уже и сам не знаю с чего начинать. Будет весьма сумбурно.
OlegAxenow, спасибо за теплые слова о нашем детище linq2db. Команда с каких-то пор интернациональная и им тоже будет приятно.
Мой ник @sdanyliv на github если что.
В linq2db CTE есть, остальное не понял ;)
При использовании linq2db я уже и не помню когда не мог создать правильный SQL через LINQ.
Вам в конечном итоге придется решать BulkCopy, временные таблицы. Все это — время.
Нужно учитывать что только SQLite и SQL Server.
Да и такой финт ушами они точно не делают https://github.com/linq2db/linq2db/pull/1278
Я бы поганял их на более сложных запросах, думаю там не все гладко.
Давно вы голову от SQL не подымали. Вот SQL Database котрорая масштабирутся и быстра как молния.
https://www.memsql.com/software/
Не заумно ли тут все написано? Хотя, ту да голый SQL или поздно и я не уловил сути.
Я делал подобный финт ушами на linq2db (C#), как-то обходился без CTE и UNION по ненадобности.
Главное правило, все что в ORDER BY дожно быть уникальным ключем и тогда такой пейджинг делается с пол пинка. Где-то у меня валялся алгоритм который любой LINQ запрос заворачивал в такой пейджинг. По заявкам откопаю.
Принцип простой, есть ORDER BY asc1, asc2, desc1 DESC
asc1 + asc2 + desc1 — обязательно уникальный ключ
Первый запуск
Берем на одну запись больше запоминаем asc1, asc2, desc1 последней записи. Также в таком варианте мы уже можем знать что страница последняя, на клиент возвращаем на одну запись меньше.
Второй запуск, следующая страница
Повторяем запоминание попоследнаей записи.
Конечно алгоритм чуток больше еще учитывал, просто передал кратко принцип
Покажите мне query decomposition на JOOQ, я задолбался искать
Хотелось бы о них услышать
Показать можете? Я смотрел на JOOQ, мило и только. Как там с переиспользванием запросв?
Это пока вам не придется писать оконные функции, Merge.
Ну в общем, ваше дело, а я прекрасно читаю LINQ и не хочу тратить время на написание SQL, склейку строк, нюансы синтаксиса. Рефакторить LINQ одно удовольствие, а вот SQL — тут
без ста грамDataGrip, еще тот квест.Вот пример, где кастомное решение рвет чистый SQL как тузик грелку:
Есть 1000 записей вида (int Id1, int Id2) в памяти приложения. Нужно выбрать из таблицы TableX все записи у которых совпадают эти два поля.
Вот решение с использованием ORM, удачи в написании SQL:
Могу и так написать, кода будет еще меньше.
Была бы база я бы выложил. MREGE синтаксис можно почитать в документации
Это с непривычки, нужно понимать что SELECT всегда в конце — иначе типы не вывести. Ну и синтаксис современного C#, не знаю как у вас с ним.
Если присмотритесть я почти не делал JOIN — все сделает библиотека через ассоциации между таблицами, их еще называют навигациями по свойствам.
Также я один раз задал фильтр по docId и больше этим не страдаю. Так уменьшается количество возможных багов (условие по JOIN неправильное, забыли фильтр наложить). Декомпозиция запросов в полный рост — то чего не хватает SQL.
Запчасти запросов я разложил по переменым, хотя можно было в некоторых местах и не делать этого. Все для того чтобы спокойно можно было каждый запрос проверить в дебаге.
К чему я веду — если иметь првильный тул, действительно можно обойтись без хранимок с минимумом оверхеда и максимальным mainteinability.
P.S.
Кстати, данный код будет работать на всех базах поддерживающих MERGE. Бибилиотека за вас учтет особенности синтаксиса нужной базы данных.
Так, для сравнения миров. Написано на C# с использованием linq2db. Все типобезопасно, те же три запроса только вставку переписал через MERGE и добавил тразакцию. Я бы с удовольствием посмотрел на код написанный спомощью JOOQ
Ну значит это не критично для вас.
Спасибо вам за DataGrip, я чесно давно не стыкался с тем что меня что-то не устаивает. По-моему вы движетесь в правильном направлении, все как програмисты любят — до мелочей.
Думаю жаловаться/предлагать надо в Github, толку больше.