Re[125]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 01.07.16 13:50
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ну почему же, вполне себе в нашей общей: http://www.tiobe.com/tiobe_index?page=index. О, я смотрю уже и мой любимый Питончик обошёл C#, забавненько... )))


Эти тесты похоже из твоей же реальности. Например, я уже лет 8 не видел и ничего не слыашал о таком редком звере как VB девелопер. А здесь он аж в десятке. О VB много пишут, это да, но пишут _о_ нём, а не _на_ нём. К тому же я ещё не разу не видел, чтобы C# шёл в рост. Он всё время падает с самого свого рождения. Т.е. с самого нуля падает и пока ещё до нуля не упал. Как такое может быть не пойму. Видимо в ваших реальностях это нормально.
Если нам не помогут, то мы тоже никого не пощадим.
Re[131]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 01.07.16 14:01
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

IT>>Во-вторых, совсем совсем статические запросы — это далеко не все запросы в приложении.

EP>Сколько статических по твоим оценкам?

Думаю, где-то 50/50 по количеству. Но статические запросы как правило простые. Динамические могут занимать не одну страницу кода.

IT>>Часто приходится формировать запросы динамически.

EP>Чем это конкретно обусловлено?

Бизнес логикой.

EP>Я к тому, что если это обусловлено например тем что итоговый запрос собирается в разных частях программы (о чём в этих темах часто и говорят), то для этого динамика не обязательна.


Поясни.
Если нам не помогут, то мы тоже никого не пощадим.
Re[119]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 01.07.16 14:05
Оценка:
Здравствуйте, alex_public, Вы писали:

_>В приведённом тобой тесте идёт сравнение исполнения через linq2db запроса записанного через linq с исполнением через ADO запроса записанного текстовой строкой. Такое сравнение не может быть использовано при обсуждение вопроса накладных расходов вносимых записью запроса через linq (почему подробно объяснено в предыдущих сообщениях данной темы).


Ты же когда говорил про 90% сравнивал LINQ именно с ADO.NET, а теперь вдруг ловишь меня на нечестности. Я даже одной секунды на эту фигню тратить не буду. Тем более, что результат будет ещё больше в пользу LINQ.
Если нам не помогут, то мы тоже никого не пощадим.
Re[131]: Тормознутость и кривость linq
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.07.16 14:06
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, IT, Вы писали:


IT>>Во-вторых, совсем совсем статические запросы — это далеко не все запросы в приложении.

EP>Сколько статических по твоим оценкам?
По моим оценкам 0.
Потому что предикаты в одних функциях, а проекции в других.
Или ты что-то другое посчитать хочешь?


EP>Я к тому, что если это обусловлено например тем что итоговый запрос собирается в разных частях программы (о чём в этих темах часто и говорят), то для этого динамика не обязательна.

Покажи пример как сделать, чтобы была необязательна. Пока этого никому не удалось.
Re[132]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 14:19
Оценка:
Здравствуйте, IT, Вы писали:

IT>>>Часто приходится формировать запросы динамически.

EP>>Чем это конкретно обусловлено?
IT>Бизнес логикой.

Небольшой пример?

EP>>Я к тому, что если это обусловлено например тем что итоговый запрос собирается в разных частях программы (о чём в этих темах часто и говорят), то для этого динамика не обязательна.

IT>Поясни.

ЕМНИП, где-то в этой, или аналогичной теме было мнение, что мол для собирания запроса по кускам необходима динамика.
На самом деле тут динамика не обязательна. Например:
auto part1()
{
    return from(foo);
}

auto part2()
{
    return part1().where(foo.id > 17);
}

void test()
{
    for(auto row : part2().select(foo.name))
        print(row.name);
}

В выделенном месте есть вся необходимая информация для построения запроса во время компиляции, то есть для такого сценария динамика не требуется.
Re[132]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 14:20
Оценка:
Здравствуйте, gandjustas, Вы писали:

IT>>>Во-вторых, совсем совсем статические запросы — это далеко не все запросы в приложении.

EP>>Сколько статических по твоим оценкам?
G>По моим оценкам 0.
G>Потому что предикаты в одних функциях, а проекции в других.

Чуть выше я как раз привёл пример именно на эту тему, там полная статика.

EP>>Я к тому, что если это обусловлено например тем что итоговый запрос собирается в разных частях программы (о чём в этих темах часто и говорят), то для этого динамика не обязательна.

G>Покажи пример как сделать, чтобы была необязательна. Пока этого никому не удалось.

Пример выше.
Re[133]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 01.07.16 14:29
Оценка: +3
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Небольшой пример?


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

EP>В выделенном месте есть вся необходимая информация для построения запроса во время компиляции, то есть для такого сценария динамика не требуется.


Это не динамика. Это декомпозиция. Вот динамика:

var q = db.Table1;

if (a != null)
    q = q.Where(t => t.Field1 == a);

if (b > 3)
    q = q.Where(t => t.Table2.Field2 != 15);
else
    q = q.Where(t => t.Table3.Field7.In("z", "y", "z"));

q.ToList();
Если нам не помогут, то мы тоже никого не пощадим.
Re[134]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 14:37
Оценка: -1
Здравствуйте, IT, Вы писали:

EP>>Небольшой пример?

IT>Например, поисковые формы. Есть 50 колонок для фильтрации запроса, а в результирующем гриде есть возможность выбирать отображаемые колонки. Под фильтрацией понимается не только фильтрация колонок в мастер таблице, но и фильтрация по колонкам связанных таблиц.

Да, тут динамика, причём здесь предварительно генерировать все варианты не разумно, ибо их очень много.

EP>>В выделенном месте есть вся необходимая информация для построения запроса во время компиляции, то есть для такого сценария динамика не требуется.

IT>Это не динамика. Это декомпозиция.

Согласен. Но вот gandjustas выше именно это и назвал динамикой, о чём я и говорил.

IT>Вот динамика:

IT>
IT>var q = db.Table1;

IT>if (a != null)
IT>    q = q.Where(t => t.Field1 == a);

IT>if (b > 3)
IT>    q = q.Where(t => t.Table2.Field2 != 15);
IT>else
IT>    q = q.Where(t => t.Table3.Field7.In("z", "y", "z"));

IT>q.ToList();
IT>


Такие запросы тоже можно сгенерировать во время компиляции — вопрос в количестве вариантов.
http://rsdn.ru/forum/flame.comp/6014522.1
Автор: Evgeny.Panasyuk
Дата: 14.04.15

Один из возможных вариантов:

auto q1 = context.Employees;
auto q2 = conditional(!IsNullOrEmpty(lastName), q1.Where(e.LastName = lastName));
auto q3 = conditional(!IsNullOrEmpty(firstName), q2.Where(e.FirstName= firstName));
auto q4 = conditional(HasValue(employmentDateFrom), q3.Where(e.EmploymentDate >= employmentDateFrom.Value));
auto q5 = conditional(HasValue(employmentDateTo)), q4.Where(e.EmploymentDate <= employmentDateTo.Value));

//далее в Presentation Layer (в другом месте)
auto list = await q5.Take(pageSize).Select(/*projection*/).ToListAsync();

При попытке выполнить этот запрос, будет произведено 4 runtime проверки, в результате чего будет выбрана одна из 16 сгенерированных в compile-time версий запроса (причём которые могут кардинально отличаться друг от друга).

Если не нравится экспоненциальное количество запросов в исполняемом файле, то можно добавить динамики. Да, при этом запрос будет частично строится в runtime (с возможным кэшированием), но при этом не будет дорогой runtime reflection — в ней тут нет принципиальной необходимости, достаточно compile-time reflection.

Re[135]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 01.07.16 14:48
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Такие запросы тоже можно сгенерировать во время компиляции — вопрос в количестве вариантов.


В этом нет смысла. Единственная проблема ET — это сложность получения хешь функции самого дерева, т.к. оно перестраивается компилятором при каждом вызове. Если делать свой собственный DSL, то такую возможность можно предусмотреть и тогда проблема кеширования запросов отпадает. Т.е. не стоит выпрыгивать из штанов в compile-time, получая неполноценный результат. Можно легко закешировать результат в run-time и жить счастливо.

Кстати, у linq2db накладные расходы на построение запроса значительно меньше остальных провайдеров только потому, что результат разбора ET кешируется. Остальные провайдеры почему-то эту возможность дружно игнорируют.
Если нам не помогут, то мы тоже никого не пощадим.
Re[136]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 15:10
Оценка:
Здравствуйте, IT, Вы писали:

EP>>Такие запросы тоже можно сгенерировать во время компиляции — вопрос в количестве вариантов.

IT>В этом нет смысла. Единственная проблема ET — это сложность получения хешь функции самого дерева, т.к. оно перестраивается компилятором при каждом вызове. Если делать свой собственный DSL, то такую возможность можно предусмотреть и тогда проблема кеширования запросов отпадает. Т.е. не стоит выпрыгивать из штанов в compile-time, получая неполноценный результат.

Не спорю, возможно и не стоит.
Я лишь говорю о том, что многие преимущества linq, в том числе и то что ты называешь главным козырем — type-safety, можно получить через генерацию compile-time, даже для динамических запросов. Насколько же это целесообразно — отдельный и важный вопрос.

IT>Можно легко закешировать результат в run-time и жить счастливо.


Размер кэша нужно ограничивать, иначе на долгоиграющей программе может вылезти та же самая комбинаторика. А раз размер ограничен, то будут переодические перевычисления вымытого из кэша.
Re[133]: Тормознутость и кривость linq
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.07.16 15:14
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Пример выше.


1) Так ты покажи макрос conditional или что там у тебя. А то так можно любой код написать и объявить его "статическим".
2) Как делать декомпозицию \ композицию таких запросов? В идеале так:http://blog.gandjustas.ru/2010/05/30/iqueryable-generics/
3) Как ты реализуешь такой сценарий:
IQueryable<X> F(IQueryable<X> xs, IEnumerable<int> m)
{
    return xs.Where(x => m.Contains(x.y));
}


Такой запрос преобразуется в
...
where x.y in (@p1, @p2,...) -- количество значений в in будет зависеть от исходного массива

?
4) Как ты сделаешь провайдеры под разные БД? (на этом alex_public посыпался)
5) Будет ли возможность сделать запрос динамическим, чтобы, например, проекция зависела от выбранных значений? Часто используется в UI и Odata сервисах.
Re[137]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 01.07.16 15:17
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Не спорю, возможно и не стоит.

EP>Я лишь говорю о том, что многие преимущества linq, в том числе и то что ты называешь главным козырем — type-safety, можно получить через генерацию compile-time, даже для динамических запросов.

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

IT>>Можно легко закешировать результат в run-time и жить счастливо.


EP>Размер кэша нужно ограничивать, иначе на долгоиграющей программе может вылезти та же самая комбинаторика. А раз размер ограничен, то будут переодические перевычисления вымытого из кэша.


Да это вообще не вопрос. В linq2db, если мне правильно подсказывает мой склероз, порядка 100 запросов на возвращаемый тип. Да и на самом деле, в обычном приложении количество различных запросов измеряется в лучшем случае несколькими сотнями. А чаще несколькими десятками.
Если нам не помогут, то мы тоже никого не пощадим.
Re[134]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 15:17
Оценка:
Здравствуйте, gandjustas, Вы писали:

EP>>Пример выше.

G>Так ты покажи макрос conditional или что там у тебя.

Функция conditional была в сообщении после того, на которое ты отвечаешь.
Я имел в виду вот этот код
Автор: Evgeny.Panasyuk
Дата: 01.07.16
— там как раз та самая декомпозиция, о которой ты говорил

EP>>Сколько статических по твоим оценкам?
G>По моим оценкам 0.
G>Потому что предикаты в одних функциях, а проекции в других.

Re[135]: Тормознутость и кривость linq
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.07.16 15:20
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, gandjustas, Вы писали:


EP>>>Пример выше.

G>>Так ты покажи макрос conditional или что там у тебя.

EP>Функция conditional была в сообщении после того, на которое ты отвечаешь.

EP>Я имел в виду вот этот код
Автор: Evgeny.Panasyuk
Дата: 01.07.16
— там как раз та самая декомпозиция, о которой ты говорил

EP>

EP>>>Сколько статических по твоим оценкам?
G>>По моим оценкам 0.
EP>G>Потому что предикаты в одних функциях, а проекции в других.


Еще раз — приведи конкретные функции. Сейчас у тебя это выглядит как магия.

auto part2()
{
    return part1().where(foo.id > 17);
}


Какой тип возвращает where? Какой тип возвращает part1()? Какой тип имеет foo.id? Как из этого потом собрать SQL без построения и обхода дерева?
Re[136]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 15:53
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Еще раз — приведи конкретные функции. Сейчас у тебя это выглядит как магия.

G>
G>auto part2()
G>{
G>    return part1().where(foo.id > 17);
G>}
G>

G>Какой тип возвращает where? Какой тип возвращает part1()?

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

Вот здесь
Автор: Evgeny.Panasyuk
Дата: 24.04.15
есть конкретный мини-пример на эту тему. Декомпозиция по функциям получается автоматически, в примере её нет, но легко добавить (live demo):
// Terminal symbols:
struct From {} from;
struct Select {} select;
struct Where {} where;

// Nonterminal:
template<typename Left, typename Right> struct Pipeline {};

template<typename T, typename U>
auto operator|(T, U)
{
    return Pipeline<T, U>{};
}

// Decomposition:
auto part1()
{
    return from;
}

auto part2()
{
    return part1() | where;
}

auto part3()
{
    return part2() | select;
}

// Utility for print type at compile time:
template<typename T> void type_is(T);

int main()
{
    type_is(part1());
    type_is(part2());
    type_is(part3());
}

Вывод:
undefined reference to `void type_is<From>(From)'
undefined reference to `void type_is<Pipeline<From, Where> >(Pipeline<From, Where>)'
undefined reference to `void type_is<Pipeline<Pipeline<From, Where>, Select> >(Pipeline<Pipeline<From, Where>, Select>)'

Жирным выделены возвращаемые типы part1, part2 и part3 соответвенно.

G>Какой тип имеет foo.id?


Технический тип placehodler, в котором закодировано что за поле и из какой таблицы.

G>Как из этого потом собрать SQL без построения и обхода дерева?


Дерево и строится и обходится, но во время компиляции.
Re[137]: Тормознутость и кривость linq
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.07.16 17:03
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Тип в который в том числе закодировано дерево выражения. На C++ это реализуется с помощью техники Expression Templates, которой уже более двадцати лет.


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

Кроме того сразу видна проблема. У тебя слишком коноетный тип, композицию сложно будет делать.
То есть from | where | select имеет тип select<where<from>>, как написать аналог функции
IQueryable<User> Active(this IQueryable<User> src) => src.Where(u => u.IsActive)

?

IQueryable может быть и результатом проекции, фильтра, группировки, чего угодно по сути.
Re[134]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 17:47
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>1) Так ты покажи макрос conditional или что там у тебя. А то так можно любой код написать и объявить его "статическим".


Я же не просто объявил, а описал механизм:

EP>При попытке выполнить этот запрос, будет произведено 4 runtime проверки, в результате чего будет выбрана одна из 16 сгенерированных в compile-time версий запроса (причём которые могут кардинально отличаться друг от друга).

Мощности шаблонов для реализации такого механизма достаточно.
Нечто схожее я реализовал вот тут
Автор: Evgeny.Panasyuk
Дата: 20.10.14
— во время компиляции строятся все варианты графа отношения порядка между элементами массива фиксированного размера, генерируется код для сортирующей перестановки каждого из вариантов, далее в runtime производятся необходимые сравнения элементов массива для выбора конкретного из всех графов, и вызов соответствующей ему перестановки.

G>2) Как делать декомпозицию \ композицию таких запросов? В идеале так:http://blog.gandjustas.ru/2010/05/30/iqueryable-generics/


В статье описана борьба с неким ограничением LINQ.

На C++ нет проблемы вынести выделенную часть из выражения
something.Where(o => o.Visible)
в отдельную сущность и прилепить её к чему угодно. Пример:
  Скрытый текст
#include <iostream>

using namespace std;

struct Foo
{
    template<typename F>
    void where(F filter)
    {
        struct
        {
            int value;
            bool visible;
        } xs[] = {{1, true}, {2, false}, {3, true}};

        cout << boolalpha;
        for(auto &x : xs)
            if(filter(x))
                cout << x.value << " " << x.visible << endl;
    }
};

/***********************************************************/
struct OnlyVisible {} only_visible;

template<typename T>
auto operator|(T x, OnlyVisible)
{
    return x.where([](auto &x){ return x.visible; });
}

int main()
{
    Foo x;

    cout << "Case #1" << endl;
    x.where([](auto &){ return true; });

    cout << "Case #2" << endl;
    x | only_visible;
}

Live Demo
Case #1
1 true
2 false
3 true
Case #2
1 true
3 true


G>3) Как ты реализуешь такой сценарий:

G>
G>IQueryable<X> F(IQueryable<X> xs, IEnumerable<int> m)
G>{
G>    return xs.Where(x => m.Contains(x.y));
G>}
G>

G>Такой запрос преобразуется в
G>
G>...
G>where x.y in (@p1, @p2,...) -- количество значений в in будет зависеть от исходного массива
G>

G>?

Структура запроса не меняется, поэтому достаточно сгенерировать в runtime только вот эту часть @p1, @p2,...

G>4) Как ты сделаешь провайдеры под разные БД? (на этом alex_public посыпался)


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

G>5) Будет ли возможность сделать запрос динамическим, чтобы, например, проекция зависела от выбранных значений? Часто используется в UI и Odata сервисах.


Да, такую возможность можно прикрутить. В любом месте где целесообразна динамика — её можно реализовать, со всеми вытекающими.
Re[135]: Тормознутость и кривость linq
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 01.07.16 18:00
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

Интересный у вас спор. Между реальной действующей системой Linq to SQL и возможностями С++.
Берется например любая конфигурация 1С и на ней тестятся все возможности Linq to EF например
http://infostart.ru/public/402038/
И аналог Linq на С++. И сравниваются возможности.
Например Code First и Linq to EF на примере 1С версии 8.3 часть II
А то у вас сравнение с сферическим конем. Возможности и реальная система это разные вещи.
C++ мощный язык, но он так же и значительно сложнее того же C#. Не говоря уже об 1С.
Можно создать кучу приблуд, только кто на нём буде программировать?
А вот на 1С программирует куча народу. В том числе потому, что язык под это заточен.
и солнце б утром не вставало, когда бы не было меня
Re[136]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 18:54
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Интересный у вас спор. Между реальной действующей системой Linq to SQL и возможностями С++.


Вообще-то не с возможностями C++, а с возможной альтернативной реализацией. На каком именно языке — C++, D, Nemerle, Rust, etc — не суть важно.

S>Берется например любая конфигурация 1С и на ней тестятся все возможности Linq to EF например

S>http://infostart.ru/public/402038/
S> И аналог Linq на С++. И сравниваются возможности.

Я не собираюсь реализовывать аналог linq + linq2db на C++ — мне это не интересно, у меня сейчас вообще нет никаких задач связанных БД

S>Возможности и реальная система это разные вещи.


И что? Речь идёт конкретно про возможности
Re[138]: Тормознутость и кривость linq
От: Evgeny.Panasyuk Россия  
Дата: 01.07.16 19:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

EP>>Тип в который в том числе закодировано дерево выражения. На C++ это реализуется с помощью техники Expression Templates, которой уже более двадцати лет.

G>Показывай минимально работающий пример, который обходит дерево и строит SQL.

Показывающий что конкретно? Проекции? Фильтры? Автоматические join'ы по связям?
Это всё ни одна сотня строк кода, реализовать которые мне не интересно.

G>Потому что построить дерево на шаблонах несложно. Самое интересное начинается дальше.


Что именно тебя смущает? Говори конкретный аспект и я расскажу (и возможно покажу) каким образом он реализуется

G>Кроме того сразу видна проблема. У тебя слишком коноетный тип


Это плата за статику.

G>, композицию сложно будет делать.

G>То есть from | where | select имеет тип select<where<from>>, как написать аналог функции
G>
G>IQueryable<User> Active(this IQueryable<User> src) => src.Where(u => u.IsActive)
G>

G>?
G>IQueryable может быть и результатом проекции, фильтра, группировки, чего угодно по сути.

Пример на эту тему я уже показал выше
Автор: Evgeny.Panasyuk
Дата: 01.07.16
.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.