SQL(sp + view || Linq)
От: divergo  
Дата: 06.03.11 17:47
Оценка:
Навеяно опросом
Автор: Shmj
Дата: 06.03.11
Вопрос: Язык SQL не очень удобен для написания логики. Но иногда полезно писать основную логику приложения в триггерах и хранимых процедурах для сокращения передаваемых данных (между базой и приложением). Как вы решаете данную проблему?
и рабочей ситуацией.

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

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

В чем суть этой "панацеи от всех бед"?
Re: SQL(sp + view || Linq)
От: Lloyd Россия  
Дата: 06.03.11 17:50
Оценка:
Здравствуйте, divergo, Вы писали:

D>Ну не вижу я никаких достоинств в написании сколько-нибудь сложных запросов на Linq.

D>Зачем?,

Типизированности недостаточно?

D>SQL привычен,


Будет linq привычен

D>хранимки быстрее,


Не быстрее

D>меньше шансов написать неоптимальный запрос.


Больше шансов написать неоптимальный код
Re: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 06.03.11 18:47
Оценка: 12 (1)
Здравствуйте, divergo, Вы писали:

D>Ну не вижу я никаких достоинств в написании сколько-нибудь сложных запросов на Linq.


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

D>Зачем?, SQL привычен, хранимки быстрее, меньше шансов написать неоптимальный запрос.


Хранимки быстрее — это анахронизм.

D>В чем суть этой "панацеи от всех бед"?


Главным образом в типизации. Как следствие, рефакторинг базы данных превращается в такое же по сложности занятие, как обычный рефакторинг кода.
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: SQL(sp + view || Linq)
От: Alexander Polyakov  
Дата: 08.03.11 19:59
Оценка: :)
Здравствуйте, IT, Вы писали:

IT>Вместо конкатенации строк в Linq можно использовать составление запросов из отдельных выражений.

Это приемлемо работает в ограниченной области, склейка строк гораздо мощнее. Ты (и никто другой) так не привел решения вот для этого примера
Автор: Alexander Polyakov
Дата: 02.11.10
(схему базы я запостил).
Re[3]: SQL(sp + view || Linq)
От: LeonidV Ниоткуда http://vygovskiy.com
Дата: 08.03.11 20:18
Оценка:
Здравствуйте, Alexander Polyakov, Вы писали:

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


IT>>Вместо конкатенации строк в Linq можно использовать составление запросов из отдельных выражений.

AP>Это приемлемо работает в ограниченной области, склейка строк гораздо мощнее. Ты (и никто другой) так не привел решения вот для этого примера
Автор: Alexander Polyakov
Дата: 02.11.10
(схему базы я запостил).

Да вообще-то я привел...
http://jvmmemory.com — простой способ настройки JVM
Re[3]: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 08.03.11 20:40
Оценка: +1
Здравствуйте, Alexander Polyakov, Вы писали:

IT>>Вместо конкатенации строк в Linq можно использовать составление запросов из отдельных выражений.

AP>Это приемлемо работает в ограниченной области, склейка строк гораздо мощнее. Ты (и никто другой) так не привел решения вот для этого примера
Автор: Alexander Polyakov
Дата: 02.11.10
(схему базы я запостил).


Немного мощнее, но и на два порядка глюкавее. Как правило базы, для которых написан такой код уже большне никогда серьёзно не рефакторятся. Само понятие "рефакторинг БД" для таких приложений представляется только как жуткий кошмар. Рефакторинг базы, для которой клиенты написаны на Linq вполне нормально рефакторятся.

Что касается твоего примера, то детально разбираться с ним в частности и с твоей задачей в целом нет ни желания, ни времени. Могу только сказать, что мы у себя генерируем Expression Tree по данным, находящимся в БД, что означает, что никаких особых проблем с генерацией ET нет. Но нужно учитывать, что общее решение для подобной задачи может вылиться в нечто весьма трудоёмкое, в то время как частные решения могут быть довольно просты. Ты искал общее решение для своего класса задач как способ подтвердить или опровергнуть возможность Linq решать такие задачи. Простого общего решения нет, частное тебя не интересует. Ну тут я
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: SQL(sp + view || Linq)
От: Alexander Polyakov  
Дата: 09.03.11 21:21
Оценка:
Здравствуйте, IT, Вы писали:

IT>Что касается твоего примера, то детально разбираться с ним в частности и с твоей задачей в целом нет ни желания, ни времени.

Тут
Автор: IT
Дата: 03.11.10
ты писал несколько иначе:

А вот со вторым EXISTS (точнее с генерацией вложенного SELECT) действительно не всё так просто. Надо подумать, может как-то можно решить и эту проблему.

По прошествии 4-х месяцев ты так и не придумал решение. Слив засчитан.
Re[5]: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 09.03.11 21:28
Оценка: :)
Здравствуйте, Alexander Polyakov, Вы писали:

AP>По прошествии 4-х месяцев ты так и не придумал решение.


Я и не думал.

AP>Слив засчитан.


Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: SQL(sp + view || Linq)
От: Кондор Россия  
Дата: 12.03.11 11:23
Оценка:
Здравствуйте, IT, Вы писали:
IT>Хранимки быстрее — это анахронизм.
Почему не быстрее? они ведь кешируются. Плюс как выяснять с linq какая часть кода провисает. В случае с хранимками
запускаем профайлер и видим что хранимка выполняется n секунд. переписываем ее и видим уже m секунд. Как подобный процесс выглядит с linq?
ДДТ!
Re[3]: SQL(sp + view || Linq)
От: Lloyd Россия  
Дата: 12.03.11 11:30
Оценка:
Здравствуйте, Кондор, Вы писали:

IT>>Хранимки быстрее — это анахронизм.

К>Почему не быстрее? они ведь кешируются.

Кешируются не хранимки, а планы sql-запросов, независимо от того, откуда взялся этот запрос — пришел из хранимки или с клиента.

К>Плюс как выяснять с linq какая часть кода провисает. В случае с хранимками

К>запускаем профайлер и видим что хранимка выполняется n секунд. переписываем ее и видим уже m секунд. Как подобный процесс выглядит с linq?

Таким же образом. Только в отличие от хранимок у нас есть полноценные профайлеры, которые могут показать, какой код сколько времени выполнялся.
Re[4]: SQL(sp + view || Linq)
От: denisio_mcp  
Дата: 12.03.11 12:32
Оценка: +1
Здравствуйте, Lloyd, Вы писали:

К>>Плюс как выяснять с linq какая часть кода провисает. В случае с хранимками

К>>запускаем профайлер и видим что хранимка выполняется n секунд. переписываем ее и видим уже m секунд. Как подобный процесс выглядит с linq?

L>Таким же образом. Только в отличие от хранимок у нас есть полноценные профайлеры, которые могут показать, какой код сколько времени выполнялся.


Вот только в случае с хранимкой ты получаешь чистое SQL-выражение которое можешь оптимизировать, а в случае Linq — у тебя добавляется ещё и ORM. И хинты не пропишешь. Сложные выражения надо бы выносить в хранимки и также из Linq дергать.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
Re[5]: SQL(sp + view || Linq)
От: Lloyd Россия  
Дата: 12.03.11 19:19
Оценка: +1
Здравствуйте, denisio_mcp, Вы писали:

L>>Таким же образом. Только в отличие от хранимок у нас есть полноценные профайлеры, которые могут показать, какой код сколько времени выполнялся.


_>Вот только в случае с хранимкой ты получаешь чистое SQL-выражение которое можешь оптимизировать, а в случае Linq — у тебя добавляется ещё и ORM. И хинты не пропишешь. Сложные выражения надо бы выносить в хранимки и также из Linq дергать.


Да, так и есть. Но сложные выражения — это дай бог 10% случаев, их не грех и руками переписать.
Re[5]: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 12.03.11 20:06
Оценка: +1
Здравствуйте, denisio_mcp, Вы писали:

_>Вот только в случае с хранимкой ты получаешь чистое SQL-выражение которое можешь оптимизировать, а в случае Linq — у тебя добавляется ещё и ORM. И хинты не пропишешь.


Это недостаток не Linq в целом, а лишь конкретных реализаций Linq-провайдеров.

_>Сложные выражения надо бы выносить в хранимки и также из Linq дергать.


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

Из опыта пользователей того же BLToolkit переписывание хранимок на Linq запросы позволяло увеличивать производительность запросов на порядок (хотя тут разница видимо в мозгах, а не в linq/stored procs). В общем, утверждение о крутости хранимок сегодня в 2011-м году весьма спорно.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: SQL(sp + view || Linq)
От: -VaS- Россия vaskir.blogspot.com
Дата: 26.03.11 09:34
Оценка:
IT>Нужно очень сильно не любить людей, чтобы заталкивать основную логику приложения в хранимки.

Не для всех типов приложений это так. Когда эта самая "основная логика" должна оперировать десятками и сотнями миллионов строк, то линки с хибернейтами дружно отправляются в сад.
Re[7]: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 26.03.11 14:12
Оценка: +1
Здравствуйте, -VaS-, Вы писали:

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

VS>Не для всех типов приложений это так. Когда эта самая "основная логика" должна оперировать десятками и сотнями миллионов строк, то линки с хибернейтами дружно отправляются в сад.

Вообще-то, Linq вполне можно использовать как генерилку SQL и все сотни миллионов строк совсем не обязательно вытаскивать на клиента, если ты об этом.
Если нам не помогут, то мы тоже никого не пощадим.
Re: SQL(sp + view || Linq)
От: rm822 Россия  
Дата: 28.03.11 21:33
Оценка:
D>Ну не вижу я никаких достоинств в написании сколько-нибудь сложных запросов на Linq.
вы не одиноки

D>В чем суть этой "панацеи от всех бед"?

ИМХО в 2х вещах
-очень удобно аспнетчикам с их стейтлесс моделью
-это что-то типа визарда\кодгенератора: пока данных мало и нагрузка мала — сойдет и так
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: SQL(sp + view || Linq)
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.03.11 01:55
Оценка: :)
Здравствуйте, divergo, Вы писали:

Главная проблема Linq в том, что он представляет собой всего одно выражение. Да, хранимки в общем случае могут быть быстрее. Но не потому что кешируется план запросов или какая-то фигня, а потому что в хранимке я могу такой код
SELECT
  X.*
FROM
  X
INNER JOIN
  Y ON Y.ID = X.ID
WHERE
  Y.Field = @Value

переписать вот так
DECLARE @PreFilteredY TABLE
(
  ID INT
);

INSERT INTO
  @PreFilteredY
SELECT
  ID
FROM
  Y
WHERE
  Y.Field = @Value

SELECT
  X.*
FROM
  X
INNER JOIN
  @PreFilteredY AS Y ON Y.ID = X.ID

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

Кроме того, да, бизнес логику в SQL часто ругают, но иногда она нужна. Практически вся сложная аналитика либо пишется в SQL коде, либо в сервер приложений выгружается пол-базы почём зря. Когда эта база 5-6Гб, а запустили отчёт в полдень четверга, идеология отходит на второй план.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[2]: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 29.03.11 02:53
Оценка: 1 (1)
Здравствуйте, adontz, Вы писали:

A>Главная проблема Linq в том, что он представляет собой всего одно выражение. Да, хранимки в общем случае могут быть быстрее. Но не потому что кешируется план запросов или какая-то фигня, а потому что в хранимке я могу такой код

A>переписать вот так

A>DECLARE @PreFilteredY TABLE
A>(
A>  ID INT
A>);

A>INSERT INTO
A>  @PreFilteredY
A>SELECT
A>  ID
A>FROM
A>  Y
A>WHERE
A>  Y.Field = @Value

A>SELECT
A>  X.*
A>FROM
A>  X
A>INNER JOIN
A>  @PreFilteredY AS Y ON Y.ID = X.ID

Под катом небольшой хелпер для DbManager:
  Скрытый текст
class MyDbManager : DbManager
{
    public Table<T> CreateTable<T>()
        where T : class
    {
        return CreateTable<T>(null);
    }

    public Table<T> CreateTable<T>(string tableName)
        where T : class
    {
        var table = new SqlTable<T>();
        var sb    = new StringBuilder();

        sb.AppendFormat("CREATE TABLE {0}\n(", tableName ?? table.Name);

        foreach (var field in table.Fields)
        {
            var f      = field.Value;
            var type   = SqlDataType.GetDataType(f.SystemType);
            var dbType = type.SqlDbType;
            var len    = type.Length > 0 ? "({0})".Args(type.Length) : type.Precision > 0 ? "({0},{1})".Args(type.Precision, type.Scale) : "";

            switch (dbType)
            {
                case SqlDbType.UniqueIdentifier :
                    dbType = SqlDbType.VarChar;
                    len    = "(36)";
                    break;
            }

            sb.AppendFormat("\n\t{0}\t{1}{2}\t{3}NULL{4},",
                f.PhysicalName,
                dbType,
                len,
                f.Nullable ? "" : "NOT ",
                f.IsIdentity ? "\t IDENTITY" : "");
        }

        sb.Length -= 1;
        sb.Append("\n)");

        SetCommand(sb.ToString());
        ExecuteNonQuery();

        var t = GetTable<T>();

        if (tableName != null)
            t = t.TableName(tableName);

        return t;
    }

    public void TruncateTable<T>()
        where T : class
    {
        var table = new SqlTable<T>();
        var sb    = new StringBuilder();

        sb.Append("TRUNCATE TABLE ");

        DataProvider.CreateSqlProvider().BuildTableName(sb, table.Database, table.Owner, table.Name);

        SetCommand(sb.ToString()).ExecuteNonQuery();
    }

    public void TruncateTable<T>(string dbName, string table)
        where T : class
    {
        var sb = new StringBuilder();

        sb.Append("TRUNCATE TABLE ");

        DataProvider.CreateSqlProvider().BuildTableName(sb, dbName, null, table);

        SetCommand(sb.ToString()).ExecuteNonQuery();
    }
}

[TableName("@PreFilteredY")
class PreFilteredY
{
    public int ID;
}

using (var db = new MyDbManager()
{
    var preFiltered = db.CreateTable<PreFilteredY>();

    db.GetTable<Y>
        .Where(y => y.Field = @Value)
        .Insert(preFiltered, y => new PreFilteredY { ID = y.ID });

    var q =
        from x in db.GetTable<X>()
        join p in preFiltered on x.ID equals p.ID
        select x;

    ...
}

A>и это (добро пожаловать в реальный мир) может в некоторых случаях работать существенно (на порядки) быстрее.

Добро пожаловать в мир BLToolkit

A>Кроме того, да, бизнес логику в SQL часто ругают, но иногда она нужна. Практически вся сложная аналитика либо пишется в SQL коде, либо в сервер приложений выгружается пол-базы почём зря. Когда эта база 5-6Гб, а запустили отчёт в полдень четверга, идеология отходит на второй план.


У нас и данных стотыщпицот гигабайт и логики не меньше. Тем не менее, с приходом Linq вся логика из базы была вычищена под корень. Ты даже не представляешь какое это счастье

Повторюсь ещё раз. Всё это не недостаток Linq в целом. Это недостатки конкретных реализаций Linq-провайдеров.
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: SQL(sp + view || Linq)
От: adontz Грузия http://adontz.wordpress.com/
Дата: 29.03.11 09:57
Оценка:
Здравствуйте, IT, Вы писали:

IT>Добро пожаловать в мир BLToolkit


Я не думаю, что ты действительно нуждаешься в моём объяснении разницы между table, temporary table и table variable.

A>>Кроме того, да, бизнес логику в SQL часто ругают, но иногда она нужна. Практически вся сложная аналитика либо пишется в SQL коде, либо в сервер приложений выгружается пол-базы почём зря. Когда эта база 5-6Гб, а запустили отчёт в полдень четверга, идеология отходит на второй план.

IT>У нас и данных стотыщпицот гигабайт и логики не меньше. Тем не менее, с приходом Linq вся логика из базы была вычищена под корень. Ты даже не представляешь какое это счастье

Представляю. Это недостижимое счастье.

IT>Повторюсь ещё раз. Всё это не недостаток Linq в целом. Это недостатки конкретных реализаций Linq-провайдеров.


Эквивалетное решение на Linq (пусть и с твоими расширениями, я не против) ты не предоставил.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[4]: SQL(sp + view || Linq)
От: IT Россия linq2db.com
Дата: 29.03.11 13:20
Оценка:
Здравствуйте, adontz, Вы писали:

IT>>Добро пожаловать в мир BLToolkit

A>Я не думаю, что ты действительно нуждаешься в моём объяснении разницы между table, temporary table и table variable.

Надеюсь тебе не надо объяснять как в приведённмо выше коде заменить слово CREATE на DECLARE?

IT>>Повторюсь ещё раз. Всё это не недостаток Linq в целом. Это недостатки конкретных реализаций Linq-провайдеров.

A>Эквивалетное решение на Linq (пусть и с твоими расширениями, я не против) ты не предоставил.

Это тебе будет домашнее задание "Ну, мы накидали идей, а вы теперь разгребайте!" (c) КВН.
Если нам не помогут, то мы тоже никого не пощадим.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.