Здравствуйте, netch80, Вы писали:
N>Вот с комбинацией C#+Unix+openpty могут быть проблемы из-за Mono (я лет 5 назад писал, как мы из-под IronPython получили слой неведомой фигни, которая подменяла честные дескрипторы файлов), но это дурость Mono, а не C# самого по себе.
Сейчас, помимо Моно, под унихами есть еще и .NET Core, качество которого намного выше (из того что я видел в исходниках — качество Core заметно выше даже родного .NET).
Здравствуйте, alex_public, Вы писали:
_>Ну вот смотри, берём там тест с названием "Simple TOP 10 query" (думаю что как раз он больше всего похож на большинство запросов в веб'е) и видим, что запрос заданный через linq исполняется в linq2db практически в 2 раза дольше, чем заданный строкой.
Ты все таки не читаешь что тебе пишут. Игорь же сказал — там не используется Compiled Query, а на таких микрозапросах, где подобные крохи на что то влияют это как раз то, для чего оно предназначено.
Здравствуйте, alex_public, Вы писали:
_>>>Откуда экспоненциально? ) Как раз чётко линейно по количеству фильтров и таблиц. _>·>Сложность условия if зависит от того в что как пересекается. _>·>В оригинальном коде — три тривиальных if (с одним условием), притом они могут стоять в любом порядке — достаточно написать три whitebox теста. В твоём коде с комбинациями условий, да в строго определённом порядке — хз... для безопасности я бы написал все восемь (23). _>И откуда ты взял бред про строго определённый порядок? )
Да, с порядком ошибся, не нужен он... т.к. эта твоя либа строит дерево выражения (как и linq), то порядок не важен.
Но всё равно, хитровывернутые комбинации условий в if создают сложность, которую придётся покрывать дополнительными тестами и тратить больше усилий при написании и поддержке кода.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Рассказы о тормозах рефлексии связаны с тем, что через рефлексию примерно на 3 порядка медленнее изменять значения свойств и вызывать методы (сейчас, кстати, там меньше 3 порядков, рассказы про то что за 10 лет ничего не изменилось по твоей ссылке — брехня). НС>Так вот, нормальный linq провайдер ничего из этого не делает. Скомпилированное компилятором шарпа дерево приложений представляет собой набор вызовов статических методов класса Expression.
Совершенно верно. Рефлексия используется для исследования объектов, а не для доступа к ним. Последний провайдер, который использовал доступа объектов был, если мне правильно подсказывает мой склероз, Subsonic. В случаях, когда linq выражение возращает не объект, а используется проекция, runtime рефлексии вообще можно избежать, т.к. компилятор вставляет в выражения токены метаданных, что-то типа methodInfo, fieldInfo, конструкции, которых нет в C#, но есть в CLR.
В общем, насчёт рефлекии можно не париться. Это давным давно решённая проблема.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
_>>Ааа, ну если переходить к таким решениям, то в итоге вообще получится плавных уход от SQL. ))) IT>А в чём проблема? Нормальное решение. Ты в курсе, что обычно самыми лучшими решениями оказываются гибридные решения? Не? Будешь знать. )
Ну я то как раз всегда был сторонником различных nosql решений) Redis, MongoDB, LevelDB и т.п.)
_>>Почему не приемлемо? ) По твоему эффективно делать новое подключение на каждый запрос? ) IT>Конечно. Есть такая штука как Connection Pool. Она замечательно решает проблему новых подключений на каждый запрос/группу запросов. Деражать подключение открытым между запросами ради Prepare абсолютно точно плохая идея.
Это ты ответил на вопрос как лучше решить проблему с новыми подключениями на каждый запрос. Но так и не ответил на вопрос чем плохо постоянное подключение.
Здравствуйте, IT, Вы писали:
_>>Ну покажи пример какого-нибудь выражения, которое на твой взгляд хорошо выглядит в linq и будет ужасно выглядеть с помощью такой библиотечки. ) IT>Так будет выглядеть любое выражение. _>>Сравним так сказать в непосредственной близости. ) IT>Гы-гы. Ты уверен? Я сейчас вытащу на свет какого-нибдуь монстрика и для тебя вечер сразу перестанет быть томным IT>Лядно, так и быть, что-нибудь попроще. Вот кусочек RSDN'а: IT>
IT>from m in db.Messages
IT>join f in db.AllowedForumsView(Account.ID) on m.ForumID equals f.ID
IT>where
IT> ids.Contains(m.ID) &&
IT> m.BlogMessages.All(bm => bm.BlogID != BlogService.Cache.GetBlogID(db, id))
IT>orderby
IT> m.Subject
IT>select
IT> m.ID + ", " + m.Subject;
IT>
Хм, что-то не очень понятно (видимо потому что я с Linq не работаю), в особенности чем являются различных идентификаторы не из таблиц (которые не m. и f.). Или может вместо объяснения ты просто покажешь какой sql генерируется из этого запроса? )
_>>Я в курсе. ) Более того, данный вопрос уже подробно обсуждался прямо в этой темке чуть выше. ) И уже был ответ на это, что это довольно странная теория, т.к. при работе скажем на голых строках в том же C# короче записать просто q+=p?"Field1=@p":"Field1 IS NULL"; IT>Ужос. Ты знаешь куда это привело человечество к концу 90-х? К BLL и DAL. Из-за того, что вот практически весь код приложений состоял из вот таких вот испражнений.
Ну да, DAL — это правильное решение для сложных проектов и особенно рассчитанных на работу с разными СУБД.
_>>вместо указанного ужастика. Но опять же это всё не касается случая C++ и той библиотечки, т.к. там вопрос с null просто не стоит. ))) IT> Т.е. глазки закрыли и мы в домике? В C++ нет налов, значит их не должно быть и в базе данных
В базе null конечно же может быть и для работы с ним там в библиотечке есть все необходимые средства (и соответствующий предикат условий и проверка результатов запросов). Автору даже предлагали сделать возврат значений для не "not null" колонок через std::optional (аналог Nullable<T> из C#), но он предпочёл обойтись проверочной функций (видимо из соображений эффективности).
Здравствуйте, alex_public, Вы писали:
_>Это ты ответил на вопрос как лучше решить проблему с новыми подключениями на каждый запрос. Но так и не ответил на вопрос чем плохо постоянное подключение.
В многозадачной/многопользовательской среде не работает. А если создавать соединение на каждую задачу/пользователя и не закрывать его, то не хватит никаких соединений. Ты же сам кажется распространялся про высоконагруженные приложения. В ADO.NET это проблему хорошо решает пул соединений, поэтому необходимости в таких решениях нет.
Если нам не помогут, то мы тоже никого не пощадим.
_>Хм, что-то не очень понятно (видимо потому что я с Linq не работаю), в особенности чем являются различных идентификаторы не из таблиц (которые не m. и f.). Или может вместо объяснения ты просто покажешь какой sql генерируется из этого запроса? )
Что-то вроде такого:
// FROM Message ,from m in db.Messages
// JOIN AllowedForumsView(@accountID) f ON m.ForumID = f.IDjoin f in db.AllowedForumsView(Account.ID) on m.ForumID equals f.ID
// WHEREwhere// m.ID IN (здесь список целочисленных констант)
ids.Contains(m.ID) &&
// EXISTS (SELECT * FROM BlogMessages.All bm WHERE m.BlogID = bm.BlogID AND bm.BolgID != @blogID)
m.BlogMessages.All(bm => bm.BlogID != BlogService.Cache.GetBlogID(db, id))
// ORDER BY m.Subjectorderby
m.Subject
// SELECT m.ID, m.Subject;select
m.ID + ", " + m.Subject;
_>Ну да, DAL — это правильное решение для сложных проектов и особенно рассчитанных на работу с разными СУБД.
DAL — это анахронизм. Тем более при работе с разными СУБД.
_>В базе null конечно же может быть и для работы с ним там в библиотечке есть все необходимые средства (и соответствующий предикат условий и проверка результатов запросов). Автору даже предлагали сделать возврат значений для не "not null" колонок через std::optional (аналог Nullable<T> из C#), но он предпочёл обойтись проверочной функций (видимо из соображений эффективности).
Понятно. Т.е. без широко обсуждаемых кастылей не обошлось.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, alex_public, Вы писали:
_>Ну я то как раз всегда был сторонником различных nosql решений) Redis, MongoDB, LevelDB и т.п.)
Кхм... Это объясняет почему ты не можешь себе представить по настоящему интенсивную работу с данными
и оперируешь какими-то выдумками, избегая конкретных корректных примеров как огня.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
_>>>Строка то всем очевидная и я её озвучил только потому, что ты признался что "Я по-разному пробовал, результат не меняется", т.е. что даже такая банальщина тебе уже не по силам. Ну так теперь, когда ты узнал как писать вменяемый код, ты понимаешь что все твои разговоры об оптимизации в той статье были бредовыми? ) Как раз из-за того что ты рассматривал только варианты хранимки vs linq. G>>Ты хочешь сказать что подобные хранимки никто никогда не пишет, а все клеят строки в прикладном коде? Ты упоротый чтоли? G>>Как раз склейкой никто не занимается, потому что это ад, а хранимки пишут гораздо чаще, чем это стоит делать.
_>Что-то у тебя в двух последовательных фразах прямое противоречие. Так хранимки надо чаще использовать или реже? )))
Надо реже, но заменять их на ручную склейку строк не все хотят. Поэтому Linq выруливает.
Просто запросы в коде приложения без склеек я приравниваю к хранимкам.
_>>>Мне не очевидно из данного кода что там за join, зачем он и вообще о чём речь. Или показывай подробнее про задачу, таблицы и т.п. или просто покажи какой генерируется итоговый sql. G>>Почему тебе не очевидно? G>>Есть товары и категории, одна категория — много товаров. У нас в каталоге товаров фильтры — один из них по категории. Небольшой кусок кода, который фильтры обрабатывает. G>>Вообще-то все поняли что я написал, даже те кто с linq не работали.
_>Ну например неясно как фильтр задаёт категорию. Т.е. если у нас ситуация, когда любой конфигурации фильтра (ну кроме null) соответствует ровно одна категория (а в твоём примере было сравнение по полю name категории, что как раз очень похоже на такой случай), то это принципиально меняет наиболее эффективный путь решения задачи.
Там же StartsWith, конечно не одному.
_>Ну и да, для случая обязательного join решение уже давно было в одном из моих сообщений выше.
Это частное решение для одного запроса. А ты, напомню, обещал универсальное решение, которое сможет генерировать широкий класс таких запросов в compile-time.
_>Но вот лично для себя меня этот вопрос всё же заинтересовал, т.к. подобных тестов я что-то не видел (что впрочем не удивительно, учитывая концепцию решения). Всё же интересно о каком порядке величины накладных расходов можно говорить в случае подобной библиотечки. Для проверки этого я набросал простенький тестовый пример для sqlite, работающий на самом базовом уровне (т.е. точно без всяких накладных расходов):
1) Выложи запускаемый код с базой
2) Убери select *, если sqlpp не умеет генерировать проекции, то лучше её сразу выкинуть
3) Покажи пример с динамически собираемым запросом, с автоматически подставляемыми джоинами. Иначе непонятно чем этот sqlpp лучше склейки строк.
Здравствуйте, IT, Вы писали:
_>>Это ты ответил на вопрос как лучше решить проблему с новыми подключениями на каждый запрос. Но так и не ответил на вопрос чем плохо постоянное подключение. IT>В многозадачной/многопользовательской среде не работает. А если создавать соединение на каждую задачу/пользователя и не закрывать его, то не хватит никаких соединений. Ты же сам кажется распространялся про высоконагруженные приложения. В ADO.NET это проблему хорошо решает пул соединений, поэтому необходимости в таких решениях нет.
Что-то ты похоже путаешь постоянные соединения и единственное на приложение. Кто тебе мешает иметь постоянное соединение в каждом потоке пула потоков?
Здравствуйте, IT, Вы писали:
_>>Хм, что-то не очень понятно (видимо потому что я с Linq не работаю), в особенности чем являются различных идентификаторы не из таблиц (которые не m. и f.). Или может вместо объяснения ты просто покажешь какой sql генерируется из этого запроса? ) IT>Что-то вроде такого:
ОК, теперь понятно. Значит сравниваем:
from m in db.Messages
join f in db.AllowedForumsView(Account.ID) on m.ForumID equals f.ID
where
ids.Contains(m.ID) &&
m.BlogMessages.All(bm => bm.BlogID != BlogService.Cache.GetBlogID(db, id))
orderby
m.Subject
select
m.ID + ", " + m.Subject;
и
auto m=DB::Messages{};
auto bm=DB::BlogMessages{};
auto f=AllowedForumsView(account_id);
auto q=select(m.ID, m.Subject)
.from(m.join(f).on(m.ForumID==f.ID))
.where(
m.ID.in(value_list(ids))&&
exists(select(all_of(bm)).from(bm).where(m.BlogID==bm.BlogID&&bm.BlogID!=id)))
.order_by(m.Subject.asc());
На мой вкус для людей знакомых с SQL второй вариант понятнее. Хотя конечно синтаксис без скобок и точек выглядит проще и яснее, но только если бы он соответствовал SQL. А в первом варианте это совсем не так (мне вот даже понадобилась "консультация" для правильного понимания этого кода).
_>>Ну да, DAL — это правильное решение для сложных проектов и особенно рассчитанных на работу с разными СУБД. IT>DAL — это анахронизм. Тем более при работе с разными СУБД.
Однако почему-то большинство веб-движков (форумы, галереи, чаты и т.п.), работающих с разными СУБД, как раз по такому принципу и построены. )
_>>В базе null конечно же может быть и для работы с ним там в библиотечке есть все необходимые средства (и соответствующий предикат условий и проверка результатов запросов). Автору даже предлагали сделать возврат значений для не "not null" колонок через std::optional (аналог Nullable<T> из C#), но он предпочёл обойтись проверочной функций (видимо из соображений эффективности). IT>Понятно. Т.е. без широко обсуждаемых кастылей не обошлось.
Здравствуйте, Ночной Смотрящий, Вы писали:
_>>В третьем случае у тебя в начале код вида if(cond) добавить_в_дерево_выражение(field>cond), а потом где-то в другом месте находится универсальный код обхода дерева (очень тормознутый кстати, причём не по вине разработчиков ORM, а из-за устройства самого .net) НС>Ты вообще читаешь что тебе пишут? Тебе несколько человек уже сказало — никакой рефлексии при обходе дерева нет. Рефлексия используется для анализа типа, описывающего метаданные самой БД. Этот тип в любом linq провайдере анализируется ровно один раз, при первом обращении, потому что типы в дотнете изменяться не могут.
А ты что под словом "рефлексия" то понимаешь? ) Похоже что-то своё особое... )))
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, IT, Вы писали:
_>>>Это ты ответил на вопрос как лучше решить проблему с новыми подключениями на каждый запрос. Но так и не ответил на вопрос чем плохо постоянное подключение. IT>>В многозадачной/многопользовательской среде не работает. А если создавать соединение на каждую задачу/пользователя и не закрывать его, то не хватит никаких соединений. Ты же сам кажется распространялся про высоконагруженные приложения. В ADO.NET это проблему хорошо решает пул соединений, поэтому необходимости в таких решениях нет.
_>Что-то ты похоже путаешь постоянные соединения и единственное на приложение. Кто тебе мешает иметь постоянное соединение в каждом потоке пула потоков?
Из пула соединений ты можешь брать любое соединение в любом потоке. Зачем лишний геморрой привязки к потоку?
Ты можешь ограничить количество соединений в пуле
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, netch80, Вы писали:
_>>Нуу накидай на C# например скриптик подключающийся параллельно к нескольким удалённым машинам (по ssh), копирующий в них некий проект и собирающий его там. Естественно с выводом всех сообщений об ошибках в локальную консоль. Сравним объём и читаемость твоего решения и решения на Питоне. ) N>Это весьма неудачный пример. Потому что если у тебя вообще есть библиотека ssh протокола для C#, вроде питоновской paramiko, то перевод логики работы с библиотекой с Питона на C# будет сделан почти автоматически, и из проблем останется только предкомпиляция. Если ты запускаешь ssh в субтерминалах, точно так же будут проблемы в аналоге openpty() (грубо говоря, требуется POSIX, а не Python).
Не, на Питоне (с использованием правильных инструментов) данный пример будет выглядеть приблизительно так:
Это весь пример целиком. И даже если предположить, что кто-то напишет похожую библиотечку для C#, то всё равно пример будет намного более громоздким за счёт синтаксического мусора в C#. )
Здравствуйте, gandjustas, Вы писали:
_>>Что-то у тебя в двух последовательных фразах прямое противоречие. Так хранимки надо чаще использовать или реже? ))) G>Надо реже, но заменять их на ручную склейку строк не все хотят. Поэтому Linq выруливает. G>Просто запросы в коде приложения без склеек я приравниваю к хранимкам.
Пока что в данном конкретном примере как раз вариант со склейкой строк является самым простым и компактным из всех остальных. Соответственно совершенно непонятно почему кто-то предпочитает ему не просто менее оптимальные, но и при этом более громоздкие варианты.
_>>Ну и да, для случая обязательного join решение уже давно было в одном из моих сообщений выше. G>Это частное решение для одного запроса. А ты, напомню, обещал универсальное решение, которое сможет генерировать широкий класс таких запросов в compile-time.
Что-что я обещал? )
_>>Но вот лично для себя меня этот вопрос всё же заинтересовал, т.к. подобных тестов я что-то не видел (что впрочем не удивительно, учитывая концепцию решения). Всё же интересно о каком порядке величины накладных расходов можно говорить в случае подобной библиотечки. Для проверки этого я набросал простенький тестовый пример для sqlite, работающий на самом базовом уровне (т.е. точно без всяких накладных расходов): G>1) Выложи запускаемый код с базой
В предыдущем сообщение как раз такой код и был. И можно сказать вместе с базой (она генерируется заново в начале каждого теста).
G>2) Убери select *, если sqlpp не умеет генерировать проекции, то лучше её сразу выкинуть
sqlpp умеет всё, что умеет sql. Не больше и не меньше. )
G>3) Покажи пример с динамически собираемым запросом, с автоматически подставляемыми джоинами. Иначе непонятно чем этот sqlpp лучше склейки строк.
Подобный пример был в предыдущих сообщениях в данной теме. Лучше склейки строк естественно статической проверкой корректности синтаксиса sql и независимостью от конкретной СУБД.
Здравствуйте, alex_public, Вы писали:
N>>Это весьма неудачный пример. Потому что если у тебя вообще есть библиотека ssh протокола для C#, вроде питоновской paramiko, то перевод логики работы с библиотекой с Питона на C# будет сделан почти автоматически, и из проблем останется только предкомпиляция. Если ты запускаешь ssh в субтерминалах, точно так же будут проблемы в аналоге openpty() (грубо говоря, требуется POSIX, а не Python).
_>
_>Это весь пример целиком. И даже если предположить, что кто-то напишет похожую библиотечку для C#, то всё равно пример будет намного более громоздким за счёт синтаксического мусора в C#. )
Ога. А ты не забыл, что Питон и Шарп практически эквивалентны в терминах возможностей ?
_>Это весь пример целиком. И даже если предположить, что кто-то напишет похожую библиотечку для C#, то всё равно пример будет намного более громоздким за счёт синтаксического мусора в C#. )
Здравствуйте, alex_public, Вы писали:
_>>>Почему не приемлемо? ) По твоему эффективно делать новое подключение на каждый запрос? ) IT>>Конечно. Есть такая штука как Connection Pool. Она замечательно решает проблему новых подключений на каждый запрос/группу запросов. Деражать подключение открытым между запросами ради Prepare абсолютно точно плохая идея.
_>Это ты ответил на вопрос как лучше решить проблему с новыми подключениями на каждый запрос. Но так и не ответил на вопрос чем плохо постоянное подключение.
А здесь ничем не отличается от джавы и тд. Держать сетевое соединение слишком дорого, база и сеть тратят на это большие ресурсы. connection pool всего лишь оптимизирует время отклика.
Здравствуйте, alex_public, Вы писали:
_>>>Хм, что-то не очень понятно (видимо потому что я с Linq не работаю), в особенности чем являются различных идентификаторы не из таблиц (которые не m. и f.). Или может вместо объяснения ты просто покажешь какой sql генерируется из этого запроса? ) IT>>Что-то вроде такого:
_>ОК, теперь понятно. Значит сравниваем: _>
_>from m in db.Messages
_>join f in db.AllowedForumsView(Account.ID) on m.ForumID equals f.ID
_>where
_> ids.Contains(m.ID) &&
_> m.BlogMessages.All(bm => bm.BlogID != BlogService.Cache.GetBlogID(db, id))
_>orderby
_> m.Subject
_>select
_> m.ID + ", " + m.Subject;
_>
_>На мой вкус для людей знакомых с SQL второй вариант понятнее. Хотя конечно синтаксис без скобок и точек выглядит проще и яснее, но только если бы он соответствовал SQL. А в первом варианте это совсем не так (мне вот даже понадобилась "консультация" для правильного понимания этого кода).
Теперь смотри фокус — в Linq ты работаешь в терминах совсем другой модели — объектной, например BlogMessages.All вернет тебе все что угодно.
Тебе же для этого 'что угодно' надо хардкодить конкретный вариант, как ты сделал через exist.
То есть, тебе надо протаскивать все намерения, детали в конкретую функцию и писать через if , что именно может быть унутре BlogMesages.All
Более того, твой SQL резко стал DB-специфик, а linq для другой базы сгенерирует другой запрос, возможно даже другой структуры. Конкретно в этом примере может и тоже самое будет, но в видео на 16й минуте можешь сам убедиться, как это происходит.