Здравствуйте, gandjustas, Вы писали:
G>>>Ну ок, возьми не C#, а любой другой статически типизированный язык. В любом языке все придет к формированию деревьев выражений на основе конструкций языка, которые потом надо будет отобразить на метаданные классов и на базе этого построить SQL. Так что накладные расходы также будут присутствовать. EP>>Вот конкретный пример: compile-time template engine
EP>>В compile-time делается анализ строки, и на основе этого генерируется определённая последовательность вызовов, результирующий ASM код получается идентичным тому, который соответствует полностью ручному оптимальному коду. G>А при чем тут Linq? Он как раз может не имея целого запроса в одном месте собрать его по кускам. Обратная задача не нужна.
При том что ты выше говорил что формирование деревьев выражений на основе конструкций языка, с отображением на классы, и последующем построением SQL будет давать накладные расходы.
Пример же показывает что возможно делать compile-time обработку без накладных расходов. Это конечно не LINQ, но представление о стоимости compile-time процессинга вполне может дать.
G>Ну ок, возьми не C#, а любой другой статически типизированный язык. В любом языке все придет к формированию деревьев выражений на основе конструкций языка, которые потом надо будет отобразить на метаданные классов и на базе этого построить SQL. Так что накладные расходы также будут присутствовать.
Дело в том что деревья выражений можно полностью обрабатывать в compile-time, точно также как и обходить метаданные классов, точно также как и строить SQL запрос по этим данным — неоткуда тут взяться накладным расходам времени выполнения.
Здравствуйте, gandjustas, Вы писали:
G>Отличный пример. Запрос секунду обрабатывался почему? Наверное потому что данные были на диске, а не в памяти. И какбы идеально, чтобы меньше запросов требовало чтения с диска. Но если у тебя часть памяти сервера скушано кешем запросов, то чтения с диска будут происходить чаще, что приведет к общему снижению быстродействия. G>Если же у тебя кеш получился высокоэффективный, и большая часть отдается из кеша, то в случае отсуствия кеша у тебя будут данные самих таблиц находиться в памяти и эффективно обслуживать все запросы, а не только те, которые совпадают буква-в-букву.
Вообще то размера кэша обычно измеряется в мегабайтах, а не гигабайтах, так что о влияние его размера на оперативную память говорить просто смешно. Но даже если бы это было и так. Ты действительно считаешь, что на маленьких (помещающихся в оперативную память) базах сумеешь добиться без кэширования времени обработки запроса измеряемого в микросекундах? )
G>Вообще MySQL изобилует сомнительными решениями, я бы не стал его в пример приводить.
http://www.oracle-developer.net/display.php?id=503 Oracle тоже является сомнительным инструментом? ))) Да, и кстати говоря... Даже если бы это работало исключительно в mysql, то твой очаровательный тезис "на уровне БД кеширования запросов нет, угадай почему" всё равно отлично демонстрировал бы твой уровень познаний. )))
Кстати, а если делать кэширование не в БД, а в приложение (как ты вроде и хотел), то как тогда проверяется, что нужные данные не изменены в БД другим приложением?
_>>Как ты думаешь, будут ли на таком фоне заметны тормоза linq или нет? ) G>Нет, даже если у тебя приложение только и делает, что получает одну и ту же строку запроса. А если приложение более сложное и делает более сложные запросы, то даже под микроскопом не различишь.
Проверим на практике? ))) Берём некую БД с кэшированием запросов и пишем к ней 3 варианта одного и того же запроса: через sql строку, через linq, через sqlpp11. И посмотрим насколько процентов будут отличаться результаты...
G>Накладыне расходы на Linq видны при масштабе. Когда у тебя тысячи запросов в секунду, убрав linq можешь получить пару процентов прироста быстродействия. А если у тебя приложение только и делает, что ждет ответ от СУБД, то отказ от Linq ничего не даст вообще.
Ну если у тебя все запросы очень медленные и нет кэширования, то возможно тормознутость linq и не заметна. Только не стоит считать, что все вокруг имеют дело с точно такой же ситуацией.
G>Я что-то не вижу как компилятор проверяет, что нельзя обращаться к row.feature если не выполнилась строка dysel.selected_columns.add(p.feature). Более того, мои знания языка C++ говорят что тип row в цикле for (const auto& row : db(dysel)) статический и проекцию никак не учитывает.
Ты что-то невнимательно читаешь опять же. Там нет вообще обращения к row.feature в случае использования dysel.selected_columns.add(p.feature) — используется другой механизм доступа к полю. Собственно обращение к row.feature вызовет ошибку компиляции (при использование dynamic_select(db).dynamic_columns(p.name).from(p).dynamic_where()) вне зависимости от наличия или отсутствия вызовов selected_columns.add(p.feature).
Однако это всё поддержка для случаев "совсем динамики", когда надо не просто сформировать динамический запрос и выполнить его, но ещё и обязательно его куда-то пересылать (т.е. чтобы у самого запроса был одинаковый тип при любом варианте ветвления) или что-то подобное. Естественно оно всё равно намного эффективнее варианта с linq, но лично я даже такое редко использую, потому как для большинства случаев (включая твой же первый пример в данной темке, который с if'ми) гораздо проще и удобнее сформировать два (ну или сколько там надо, в зависимости от количества ветвлений) статических запроса и сразу же выполнить их по месту.
G>Или например джоин: G>
G>Я не очень понимаю как компилятор будет проверять, что указанное в select реально есть в таблицах, указанных во from. Аналогичная проблема в предикатом джоина, неясно как проверяется что выражение в предикате соответствует таблицам во from и join.
Нуу ты приглядись к select повнимательнее — на самом деле таблицы указаны прямо в нём (p и x же имеют свои типы). Т.е. поле from реально приносит пользу только как раз для всяких там join и т.п., а в обычных запросах присутствует скорее для красоты (хотя если передать туда неверную таблицу, то всё равно будет ошибка).
G>Так что я не верю что такм такой же уровень типизации, как в Linq. Покажи пример что будет если попробовать составить неправильный запрос. G>А также приведи пример как навесить джоин на уже существующий запрос.
select.cpp:60:20: error: 'const struct sqlpp::result_row_t<MockDbT<false>, sqlpp::field_spec_t<test::TabPerson_::Name::_alias_t, sqlpp::text, false, false> >' has no member named 'id'
int64_t id = row.id;
^
select.cpp:62:25: error: 'const struct sqlpp::result_row_t<MockDbT<false>, sqlpp::field_spec_t<test::TabPerson_::Name::_alias_t, sqlpp::text, false, false> >' has no member named 'feature'
int64_t feature = row.feature; ^
Да, и правильно что не веришь (вообще конечно это интересное слово в устах инженера...), что тут всё так же как в linq. Потому как тут очевидно лучше и эффективнее. )))
_>>Зато в библиотечке примеры вполне даже компилируемые. Но ты их похоже принципиально не замечаешь. ) G>Только там от силы 10% того, что умеет linq. G>Тут два варианта: или больше не умеет, или не все так хорошо, как ты описываешь. G>Поэтому приведи аналог того примера, что я писал и мы поверим. А пока — увы. Аналогов linq и близко нет.
Эм, а с чего ты взял, что тут кто-то пытается создать аналог linq? ) Пытаться повторить кривой инструмент? Нет, спасибо, такого не надо. Нам нужно построить удобный и эффективный инструмент для работы с SQL БД. И мы этот инструмент имеем — полное статически типизрованное отражение sql в язык.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А почему предпочитаешь "лёгкие" решения? EP>Я понимаю если база данных уже есть сама по себе, и всё что нужно это сделать несколько запросов — то тут конечно "лёгкие" решения оптимальны. EP>Но если же нам нужно отображать развесистую модель данных на БД, которая при этом ещё и изменяется во времени — то ведь в этом случае больше подходит "тяжёлый комбайн", нежели рукопашная реализация его фич поверх "лёгких" решений.
Нуу т.к. у меня задачи обычно где-то посередине между этими двумя крайностями (БД создаётся под приложение, но при этом обычно неизменна на протяжение жизни), то тут уже выбор становится по сути делом вкуса. ))) Ну а т.к. я вообще не очень люблю какие-либо фреймворки, то... )
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>То есть обычно ORM используют третий (смешанный) вариант, отсюда и проблемы?
ORM, которые бы навязывали хранимки, мне неизвестны. Но зачастую смешанный вариант используют поклонники хранимок как решения проблемы производительности ORM. Просто потому, что не отдают себе отчёта в этой проблеме, и у них нет мотивации идти до конца — т.е. превращать SQL в сервер приложений, мигрируя в хранимки/триггеры/view всю прикладную логику.
EP>Например в ODB вся логика обработки данных содержится в одном месте. И если, например, произойдёт откат базы — то при доступе к ней произойдёт обновление схемы и миграция данных (причём есть опция постепенного перехода).
Звучит неплохо. Подробности надо изучать. Во времена, когда я этим интенсивно занимался, никаких ODB ещё не было. Были Versant, Gemstone, а ORM существовали в виде рекомендаций Фаулера, а не готовых фреймворков.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
_>Ну так мы же можем без проблем реализовать такое на уровне склейки sql строк, не так ли? ) Тогда почему возникают сомнения, что можно написать статически типизируемый код, который компилируется в полный аналог такой склейки строк?
Потому, что вы уже пять сообщений подряд уклоняетесь от того, чтобы показать нам этот код. _>Гмммм, насколько я помню, ты же вроде в курсе C++. Тогда откуда такие вопросы? Это же вот прямо самый базисный принцип программирования на шаблонах C++, из-за которого разбухают итоговые бинарники, но при этом достигается непревзойдённая производительность.
Это общие слова. Пока что я не вижу способа, которым бы они воплотились в действие. Вы покажите код, чтобы было что обсуждать. Базисные принципы программирования тут неинтересны — их так много, что можно подвести подходящий принцип под любое высказывание и под его отрицание.
_>Ммм, варианта от Евгения мало что ли? )
Он использует какую-то другую библиотеку, чем вы (причём непонятно какую).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
EP>Это не в C++ взаимоисключающие, а по сути. То есть даже при использовании внешнего генератора (с любым языком), в случае с .dll из пункта 1, есть выбор: EP>* либо выносить в интерфейс "жёсткий" тип запроса, который при изменении запроса будет меняться (и требовать переборки зависимого кода), но что позволит в месте вызова запроса производить полную compile-time обработку, без всякого runtime overhead'а. EP>* либо же делать стирание типа, что даст "мягкий" тип запроса, который не будет зависеть от его мелких деталей, но при этом мы неизбежно получаем runtime penalty — так как в месте вызова запроса мы уже не знаем всех его деталей во время компиляции, и полностью построить его в compile-time не сможем.
EP>Этот выбор продиктован не какими-то недостатками C++, а самой задачей, и не зависит от языка/технологии. Там где нужна динамика приходится платить в рантайме.
Опять чуда не случилось. C++ со всем метапрограммированием помогает только в статическом случае, который с точки зрения генерации SQL даже неинтересен. А когда динамика, то ничего близкого к linq нету. Хотя изначально утверждалось обратное.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, gandjustas, Вы писали:
EP>При том что ты выше говорил что формирование деревьев выражений на основе конструкций языка, с отображением на классы, и последующем построением SQL будет давать накладные расходы. EP>Пример же показывает что возможно делать compile-time обработку без накладных расходов. Это конечно не LINQ, но представление о стоимости compile-time процессинга вполне может дать.
Да ни о чем пример, так как он статическую строку обрабатывает.
EP>Дело в том что деревья выражений можно полностью обрабатывать в compile-time, точно также как и обходить метаданные классов, точно также как и строить SQL запрос по этим данным — неоткуда тут взяться накладным расходам времени выполнения.
Это только в случае статического дерева, который крайне неинтересен.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Отличный пример. Запрос секунду обрабатывался почему? Наверное потому что данные были на диске, а не в памяти. И какбы идеально, чтобы меньше запросов требовало чтения с диска. Но если у тебя часть памяти сервера скушано кешем запросов, то чтения с диска будут происходить чаще, что приведет к общему снижению быстродействия. G>>Если же у тебя кеш получился высокоэффективный, и большая часть отдается из кеша, то в случае отсуствия кеша у тебя будут данные самих таблиц находиться в памяти и эффективно обслуживать все запросы, а не только те, которые совпадают буква-в-букву.
_>Вообще то размера кэша обычно измеряется в мегабайтах, а не гигабайтах, так что о влияние его размера на оперативную память говорить просто смешно. Но даже если бы это было и так. Ты действительно считаешь, что на маленьких (помещающихся в оперативную память) базах сумеешь добиться без кэширования времени обработки запроса измеряемого в микросекундах? )
Если кеш меряется в мегабайтах, то это настолько маленькая база, что нет смысла говорить о быстродействии. Её можно полностью затянуть в память приложения и по ней ходить. Естественно в этом случае скорость выполнения запросов составит микросекунды.
G>>Вообще MySQL изобилует сомнительными решениями, я бы не стал его в пример приводить.
_>http://www.oracle-developer.net/display.php?id=503 Oracle тоже является сомнительным инструментом? ))) Да, и кстати говоря... Даже если бы это работало исключительно в mysql, то твой очаровательный тезис "на уровне БД кеширования запросов нет, угадай почему" всё равно отлично демонстрировал бы твой уровень познаний. )))
А ты по ссылкам не читал дальше? Вот например http://www.pythian.com/blog/oracle-11g-result-cache-tested-on-eight-way-itanium/
Оказывается кеш в оракле плохо масштабируется, и по умолчанию он выключен. Видимо для очень специфических сценариев применяется. Включенного кеша я ни на одном оракловом сервере не видел.
_>Кстати, а если делать кэширование не в БД, а в приложение (как ты вроде и хотел), то как тогда проверяется, что нужные данные не изменены в БД другим приложением?
Ты удивишься, но 90%+ критичных к скорости приложений не допускают в базу другие приложения. В оставшихся 10% можно таймстемпы и тригеры прикрутить.
_>Проверим на практике? ))) Берём некую БД с кэшированием запросов и пишем к ней 3 варианта одного и того же запроса: через sql строку, через linq, через sqlpp11. И посмотрим насколько процентов будут отличаться результаты...
Вперед, пиши. Пример на C# я привел, давай аналогичный на голом SQL и sqlpp11.
Еще раз напомню, что ты утверждал, что можно сделать быстрее без потери возможностей linq. Вот и делай пример.
G>>Накладыне расходы на Linq видны при масштабе. Когда у тебя тысячи запросов в секунду, убрав linq можешь получить пару процентов прироста быстродействия. А если у тебя приложение только и делает, что ждет ответ от СУБД, то отказ от Linq ничего не даст вообще.
_>Ну если у тебя все запросы очень медленные и нет кэширования, то возможно тормознутость linq и не заметна. Только не стоит считать, что все вокруг имеют дело с точно такой же ситуацией.
Случай примитивных запросов рассматривать неинтересно. В linq их можно прогнать через compiled query и расходы на создание\обход деревьев упадут до нуля.
G>>Я что-то не вижу как компилятор проверяет, что нельзя обращаться к row.feature если не выполнилась строка dysel.selected_columns.add(p.feature). Более того, мои знания языка C++ говорят что тип row в цикле for (const auto& row : db(dysel)) статический и проекцию никак не учитывает.
_>Ты что-то невнимательно читаешь опять же. Там нет вообще обращения к row.feature в случае использования dysel.selected_columns.add(p.feature) — используется другой механизм доступа к полю. Собственно обращение к row.feature вызовет ошибку компиляции (при использование dynamic_select(db).dynamic_columns(p.name).from(p).dynamic_where()) вне зависимости от наличия или отсутствия вызовов selected_columns.add(p.feature).
То есть я добавил в проекцию поле и не могу обратиться к нему? Это гениально!
_>Однако это всё поддержка для случаев "совсем динамики", когда надо не просто сформировать динамический запрос и выполнить его, но ещё и обязательно его куда-то пересылать (т.е. чтобы у самого запроса был одинаковый тип при любом варианте ветвления) или что-то подобное. Естественно оно всё равно намного эффективнее варианта с linq, но лично я даже такое редко использую, потому как для большинства случаев (включая твой же первый пример в данной темке, который с if'ми) гораздо проще и удобнее сформировать два (ну или сколько там надо, в зависимости от количества ветвлений) статических запроса и сразу же выполнить их по месту.
Понятно, значит ничего не умеет, так и запишем.
У меня был код, в котором linq запрос формировался с учетом около 8 параметров. Это 256 вариантов (на практике около 150 корректных). Посмотрю я как ты их все выписывать будешь.
_>Нуу ты приглядись к select повнимательнее — на самом деле таблицы указаны прямо в нём (p и x же имеют свои типы). Т.е. поле from реально приносит пользу только как раз для всяких там join и т.п., а в обычных запросах присутствует скорее для красоты (хотя если передать туда неверную таблицу, то всё равно будет ошибка).
То есть типизированных джоинов тоже нет.
Ладно, продолжать неинтересно. Я уже увидел что от силы 10% возможностей linq покрывается, и то самых простых.
Когда в теме сошлись такие дотнетчики, как gandjustas, и плюсисты, как Evgeny.Panasyuk и alex_public, мне стало ясно, как будет идти их общение. Крестоносцы будут говорить, что в плюсах можно сделать всё (и даже больше!), а шарписты требовать: ты покажи именно то, что я написал!
Припоминается такой же стиль общения в теме по async.
И, как и в прошлый раз, я напишу следующее: имхо, C++ действительно позволяет всё то, что есть в C#/linq. Но дело в том, что linq/EF в мире .NET — это обыденная вещь, которую используют даже начинающие. А в C++ использование метапрограммирования и всех тех вкусностей, что приводили вышеупомянутые товарищи, доступно лишь немногим джедаям, и уж точно не новичку.
Здравствуйте, koodeer, Вы писали:
K>Когда в теме сошлись такие дотнетчики, как gandjustas, и плюсисты, как Evgeny.Panasyuk и alex_public, мне стало ясно, как будет идти их общение. Крестоносцы будут говорить, что в плюсах можно сделать всё (и даже больше!), а шарписты требовать: ты покажи именно то, что я написал!
Тут всё же дискуссия не о том как сделать LINQ в C++, а о том что этот самый LINQ в большинстве случаев может быть/(мог бы быть) более оптимальным, даже в том же C#. То есть всё закрутилось вокруг:
G>>Ты ищешь какие-то накладные расходы в linq, хотя я тебе уже написал, что это обход expression tree, от которого ты никуда не денешься, какой бы DSL ты не создал.
_>Это вполне может отрабатываться на этапе компиляции.
В рамках C++ это возможно, но с заморочками, так ещё нет встроенного compile-time reflection. В рамках D и Nemerle это тоже возможно, но намного проще чем в C++. А вот в C#, насколько я вижу, это невозможно, но вполне реализуемо в качестве внешнего инструмента.
Здравствуйте, koodeer, Вы писали:
K>И, как и в прошлый раз, я напишу следующее: имхо, C++ действительно позволяет всё то, что есть в C#/linq. Но дело в том, что linq/EF в мире .NET — это обыденная вещь, которую используют даже начинающие. А в C++ использование метапрограммирования и всех тех вкусностей, что приводили вышеупомянутые товарищи, доступно лишь немногим джедаям, и уж точно не новичку.
Пока никто не показал типизированные проекции и джоины в динамических запросах. Примерно та же проблема, что и с другими фичами яызка. Можно отдаленно повторить, если обвесить тонной макросов и шаблонов, в которых кроме автора никто не разберется в жизни.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, koodeer, Вы писали:
K>>Когда в теме сошлись такие дотнетчики, как gandjustas, и плюсисты, как Evgeny.Panasyuk и alex_public, мне стало ясно, как будет идти их общение. Крестоносцы будут говорить, что в плюсах можно сделать всё (и даже больше!), а шарписты требовать: ты покажи именно то, что я написал!
EP>Тут всё же дискуссия не о том как сделать LINQ в C++, а о том что этот самый LINQ в большинстве случаев может быть/(мог бы быть) более оптимальным, даже в том же C#.
Но вот примеров чего угодно с возможностями linq для построения запросов к базе мы не увидели. То что некоторые примеры на примитивных случаях работают быстрее не имеет никакой практической пользы.
EP>В рамках C++ это возможно, но с заморочками, так ещё нет встроенного compile-time reflection. В рамках D и Nemerle это тоже возможно, но намного проще чем в C++. А вот в C#, насколько я вижу, это невозможно, но вполне реализуемо в качестве внешнего инструмента.
Я вроде писал тебе про compiled query. В статическом случае все запросы прогоняются через него. А "с заморочками" вполне можно написать плагин компилятора, который эту операцию автоматизирует. То есть все статические запросы (определенные целиком внуnри метода без ветвлений), можно превратить в статические поля, которые созданы с помощью compiled query. И будут нулевые затраты.
Но это даст такой мизер, что имеет смысл заниматься минимум при масштабе StackOverflow.
Здравствуйте, gandjustas, Вы писали:
EP>>В рамках C++ это возможно, но с заморочками, так ещё нет встроенного compile-time reflection. В рамках D и Nemerle это тоже возможно, но намного проще чем в C++. А вот в C#, насколько я вижу, это невозможно, но вполне реализуемо в качестве внешнего инструмента. G>Я вроде писал тебе про compiled query. В статическом случае все запросы прогоняются через него.
При этом обходятся ET через runtime reflection
G>А "с заморочками" вполне можно написать плагин компилятора, который эту операцию автоматизирует. То есть все статические запросы (определенные целиком внуnри метода без ветвлений), можно превратить в статические поля, которые созданы с помощью compiled query. И будут нулевые затраты.
О чём собственно и речь, но ты почему-то говорил что это невозможно:
G>Ты ищешь какие-то накладные расходы в linq, хотя я тебе уже написал, что это обход expression tree, от которого ты никуда не денешься, какой бы DSL ты не создал.
G>Ну ок, возьми не C#, а любой другой статически типизированный язык. В любом языке все придет к формированию деревьев выражений на основе конструкций языка, которые потом надо будет отобразить на метаданные классов и на базе этого построить SQL. Так что накладные расходы также будут присутствовать.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, gandjustas, Вы писали:
EP>>>В рамках C++ это возможно, но с заморочками, так ещё нет встроенного compile-time reflection. В рамках D и Nemerle это тоже возможно, но намного проще чем в C++. А вот в C#, насколько я вижу, это невозможно, но вполне реализуемо в качестве внешнего инструмента. G>>Я вроде писал тебе про compiled query. В статическом случае все запросы прогоняются через него.
EP>При этом обходятся ET через runtime reflection
Это не так. Но незнание деталей тебе простим.
G>>А "с заморочками" вполне можно написать плагин компилятора, который эту операцию автоматизирует. То есть все статические запросы (определенные целиком внуnри метода без ветвлений), можно превратить в статические поля, которые созданы с помощью compiled query. И будут нулевые затраты.
EP>О чём собственно и речь, но ты почему-то говорил что это невозможно: EP>
G>>Ты ищешь какие-то накладные расходы в linq, хотя я тебе уже написал, что это обход expression tree, от которого ты никуда не денешься, какой бы DSL ты не создал.
EP>
G>>Ну ок, возьми не C#, а любой другой статически типизированный язык. В любом языке все придет к формированию деревьев выражений на основе конструкций языка, которые потом надо будет отобразить на метаданные классов и на базе этого построить SQL. Так что накладные расходы также будут присутствовать.
Я изначально говорил о динамической композиции запросов. И примеры приводил соответствующие. Если вы не удосужились пример прочитать и понять его суть, то зачем вообще спорить начали?
Вся тема началась с того, что кому-то не понравился EF и было предложение использовать хранимки. Но хранимки часто получаются медленнее, чем склейка запросов, которую прекрасно автоматизирует linq (linq2db, EF, linq2sql). Вообще не было речи о статических примитивных запросах. Это уже ты и _alex_public_ начали выкручиваться, сводя разговор к примитивным случаям.
Здравствуйте, gandjustas, Вы писали:
EP>>>>В рамках C++ это возможно, но с заморочками, так ещё нет встроенного compile-time reflection. В рамках D и Nemerle это тоже возможно, но намного проще чем в C++. А вот в C#, насколько я вижу, это невозможно, но вполне реализуемо в качестве внешнего инструмента. G>>>Я вроде писал тебе про compiled query. В статическом случае все запросы прогоняются через него. EP>>При этом обходятся ET через runtime reflection G>Это не так. Но незнание деталей тебе простим.
Что конкретно не так?
Компиляция compiled query происходит не в runtime? Или в runtime, но не через runtime reflection?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Что конкретно не так? EP>Компиляция compiled query происходит не в runtime? Или в runtime, но не через runtime reflection?
Она происходит один раз, а значит ей можно пренебречь.
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
EP>>Что конкретно не так? EP>>Компиляция compiled query происходит не в runtime? Или в runtime, но не через runtime reflection? WH>Она происходит один раз, а значит ей можно пренебречь.
С этим не буду спорить. Но тут-то речь о другом шла:
G>>>Я вроде писал тебе про compiled query. В статическом случае все запросы прогоняются через него.
EP>>При этом обходятся ET через runtime reflection
G>Это не так. Но незнание деталей тебе простим.
Здравствуйте, gandjustas, Вы писали:
EP>>О чём собственно и речь, но ты почему-то говорил что это невозможно: EP>>
G>>>Ты ищешь какие-то накладные расходы в linq, хотя я тебе уже написал, что это обход expression tree, от которого ты никуда не денешься, какой бы DSL ты не создал.
EP>>
G>>>Ну ок, возьми не C#, а любой другой статически типизированный язык. В любом языке все придет к формированию деревьев выражений на основе конструкций языка, которые потом надо будет отобразить на метаданные классов и на базе этого построить SQL. Так что накладные расходы также будут присутствовать.
G>Я изначально говорил о динамической композиции запросов.
Где? После приведённых выше цитат?
G>И примеры приводил соответствующие.
Пример был после цитат.
G>Если вы не удосужились пример прочитать и понять его суть, то зачем вообще спорить начали?
этого примера, с комментариями. По комментариям разве не видно что пример я прочитал и понял — если же не согласен, то покажи конкретное место которое я не понял или не прочёл.
G>Вся тема началась с того, что кому-то не понравился EF и было предложение использовать хранимки. Но хранимки часто получаются медленнее, чем склейка запросов, которую прекрасно автоматизирует linq (linq2db, EF, linq2sql).
Мы находимся в под-теме, и EF вообще не обсуждаем.
G>Вообще не было речи о статических примитивных запросах. Это уже ты и _alex_public_ начали выкручиваться, сводя разговор к примитивным случаям.
Согласен с тем что деревья выражений всё-таки можно обходить без накладных расходов в compile-time (даже при динамической композиции, но уже частично; например те самые "16 сгенерированных в compile-time версий запроса" по четырём условиям)?
Здравствуйте, gandjustas, Вы писали:
G>Если кеш меряется в мегабайтах, то это настолько маленькая база, что нет смысла говорить о быстродействии. Её можно полностью затянуть в память приложения и по ней ходить. Естественно в этом случае скорость выполнения запросов составит микросекунды.
Откуда это тебе знать? ) Ты же до этого момента даже не подозревал о существование таких кэшей. А тут вдруг резко стал экспертом по их работе? )))
G>А ты по ссылкам не читал дальше? Вот например http://www.pythian.com/blog/oracle-11g-result-cache-tested-on-eight-way-itanium/ G>Оказывается кеш в оракле плохо масштабируется, и по умолчанию он выключен. Видимо для очень специфических сценариев применяется. Включенного кеша я ни на одном оракловом сервере не видел.
Я уже не сомневаюсь, что ты придумаешь отмазку на любой аргумент (и на любые другие БД). ))) Однако это всё равно не поможет — картина уже понятна. )))
G>Ты удивишься, но 90%+ критичных к скорости приложений не допускают в базу другие приложения. В оставшихся 10% можно таймстемпы и тригеры прикрутить.
Ну так могут быть например просто несколько процессов одного и того же приложения. Как я понимаю, твоё решение в таком случае будет совсем печальным по быстродействию? )
_>>Проверим на практике? ))) Берём некую БД с кэшированием запросов и пишем к ней 3 варианта одного и того же запроса: через sql строку, через linq, через sqlpp11. И посмотрим насколько процентов будут отличаться результаты... G>Вперед, пиши. Пример на C# я привел, давай аналогичный на голом SQL и sqlpp11. G>Еще раз напомню, что ты утверждал, что можно сделать быстрее без потери возможностей linq. Вот и делай пример.
string query="select first_name, last_name, employment_date from Employees where 1";
if(!first_name.empty()) query+=" and first_name=\""+first_name+'"';
if(!last_name.empty()) query+=" and last_name=\""+last_name+'"';
if(employment_date_from) query+=" and employment_date>="+to_string(employment_date_from);
if(employment_date_to) query+=" and employment_date<"+to_string(employment_date_to);
Как будем измерять? ) Напомню, что хочется особенно посмотреть на кэшированных запросах (которые меньше миллисекунды "исполняются").
G>Случай примитивных запросов рассматривать неинтересно. В linq их можно прогнать через compiled query и расходы на создание\обход деревьев упадут до нуля.
"Можно" — это конечно хорошо звучит. Так покажи, как такой код будет выглядеть на практике. Вот опять же на базе того твоего примера с if'ми. )))
G>То есть я добавил в проекцию поле и не могу обратиться к нему? Это гениально!
Можешь, но через специальную функцию, а не в виде обычного поля) Т.к. собственно ситуация динамической проекции (в отличие от динамических запросов) является совсем нестандартным случаем.
G>Понятно, значит ничего не умеет, так и запишем.
Ну если ты смог только такое понять, после просмотра тех примеров, то тогда сочувствую. )))
G>То есть типизированных джоинов тоже нет.
И снова у тебя плохо с чтением. Если ты потребуешь не то поле, то получишь ошибку. ) Я тебе об этом писал ещё в предыдущем сообщение.
G>Ладно, продолжать неинтересно. Я уже увидел что от силы 10% возможностей linq покрывается, и то самых простых.
Здравствуйте, koodeer, Вы писали:
K>Когда в теме сошлись такие дотнетчики, как gandjustas, и плюсисты, как Evgeny.Panasyuk и alex_public, мне стало ясно, как будет идти их общение. Крестоносцы будут говорить, что в плюсах можно сделать всё (и даже больше!), а шарписты требовать: ты покажи именно то, что я написал!
K>Припоминается такой же стиль общения в теме по async.
K>И, как и в прошлый раз, я напишу следующее: имхо, C++ действительно позволяет всё то, что есть в C#/linq. Но дело в том, что linq/EF в мире .NET — это обыденная вещь, которую используют даже начинающие. А в C++ использование метапрограммирования и всех тех вкусностей, что приводили вышеупомянутые товарищи, доступно лишь немногим джедаям, и уж точно не новичку.
Всё верно сказано. Но есть один неучтённый нюанс. В C++ действительно сложно заниматься метапрограммированием. А вот пользоваться результатами метапрограммирования обычно как раз наоборот очень просто и удобно. Т.е. грубо говоря, если по данной тематике существует проработанная готовая библиотека, то не смотря на дикую жуть внутри, пользоваться ею сможет даже новичок. Собственно по async такой библиотеки в то время не было и пришлось писать свою реализацию, а вот по sql, как видно, всё есть и даже не одна.