Re[19]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 30.06.14 07:56
Оценка:
Здравствуйте, IT, Вы писали:

IT> Т.е. начинаю я работать над какой-нибудь формой и мне нужно заполнить её данными, пока двумя полями. Я зову Васю-Специалиста-На-Базах-И-Запросах и он пишет мне в моём коде SQL, который читает эти два поля для меня из базы. Через 10 минут мне надо подчитать третье поле, я опять зову Васю-Специалиста-На-Базах-И-Запросах и он мне дописывает SQL по требованию. Потом мне нужно будет добавить четвёртое поле, сделать группировку, чего-нибудь отфильтровать и каждый раз мне нужно будет звать Васю-Специалиста-На-Базах-И-Запросах. Тебе самому не смешно?


Еще смешнее становится когда грид-контрол умеет сортировки, фильтрацию и группировки.
Re[22]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 30.06.14 08:03
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>1) "Дошло" до команды EF только тогда, когда понадобилось портировать EF на WinRT


Докажи что именно это послужило причиной. Пока что твои заявления голословны.

G>2) Куча редкоиспользуемых фич никого не беспокоит


Авторов, вишь, таки беспокоит.
Re[22]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.06.14 08:32
Оценка:
Здравствуйте, IT, Вы писали:

IT>>>Во-первых, написание полноценного Linq-провайдера — это не тривиальная задача типа unit testing framework. Лет пять назад в MS эту задачу оценивали в пару лямов.

G>>Слабая отмазка, в Open Source уже немерено этих провайдеров, а IQToolkit появился вместе с .NET 3.5. Если бы новый провайер мог решить реальные проблемы, а не сущетвующие только в голове отдельных личностей, то уже давно бы это сделали.

IT>Отмазка вполне серьёзная. Тот же IQToolkit более как на роль примера linq-провайдера больше ни на что не тянет. Реально его пытался использовать только автор Subsonic, который в результате на OrmMetter не был допущен к забегу в категории linq из-за фейла почти всех linq-тестов.

IT>В общем, если бы я точно знал куда я лезу, когда начинал заниматься linq-провайдером в BLT, то точно бы не стал этого делать и сейчас, скорее всего восхвалял EF вместе с тобой и точно так же спорил бы с IB
А почему? Решение проблем не стоит затраченных усилий? Тогда за что EF ругают?

IT>>>В-третьих, сделали. linq2db не страдает ORM-ностью и представляет собой скорее типизированный SQL.

G>>И что? Проблемы решились? Где толпы восторженных пользователей? Гуглг по linq2db находит репы,
IT>Я программист, а не пиарщик. Видимо в этом проблема. К тому же см. выше про ресурсы. Кто-то их тратит на написание кода, а кто-то на толпы восторженных пользователей.
Без реального фидбека хороший продукт не получится. А фидбек получить без контента не получится.

G>>целое одно сообщение на rsdn давностью больше полугода.

IT>Вообще-то есть целый форум про это дело. К тому же linq2db это как раз переработка BLT в части linq и всё, что касается BLT можно отнести к linq2db.
Я не про форум, а про гугл. Главное правило интернета — если тебя не находит гугл, значит тебя не существует.

G>>Верю. И что? Для меня вообще скорость маппинга не была никогда проблемой.

IT>Тогда зачем ты это приводил в качестве аргумента? На самом деле метапрограммирование в этом деле вовсе не бесполезно. Например, модель данных запросто можно генерировать в момент компиляции, а не с помощью T4.
Потому что для многих в этой теме это проблема (по неясным для меня причинам).

G>>Кстати для замеров добавил linq2db в тестовый проект, оказалось что TT генератор хреново работает с базами, у которых точки в имени,

IT>Давай пофиксим вместо. Давай пример неработающего кода, будем фиксить.

В TT файле:

LoadSqlServerMetadata(@".", "DataBaseName.WithDot");


Генерит имя класса DataBaseName.WithDot, что вызывает ошибку компиляции.

Скорее всего с именами полей та же проблема будет.


G>>а также напрягло что завязано на .config файл. В KRuntime хотят отказаться от идеи обязательного конфига, да и сейчас много сред, где конфиг недоступен.


IT>Всё можно сконфигурировать и без конфигов. Последние пять лет у меня это вообще была единственная доступная опция.

Нельзя передать в конструктор контекста строку подключения
Re[23]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.06.14 08:41
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


G>>1) "Дошло" до команды EF только тогда, когда понадобилось портировать EF на WinRT

НС>Докажи что именно это послужило причиной. Пока что твои заявления голословны.
В том же пресс-релизе написано в самом начале:

Entity Framework is a popular data access choice for traditional client and server applications that target the full .NET Framework. This includes applications built with technologies such as WPF, WinForms and ASP.NET. As we look to the future, we believe there is value in providing the same programming model for data access on the remaining platforms where .NET development is common. This includes Windows Store, Windows Phone and the Cloud Optimized .NET that was announced at TechEd. EF7 will work on all of these platforms as well as Mono, on both Mac and Linux.


Далее смотрим в wiki: https://github.com/aspnet/EntityFramework/wiki/Getting-and-Building-the-Code
Выясняется что EF разрабатывается под K Runtime. который использует .NET Core Runtime (общий знаменатель для всех версий .NET)


G>>2) Куча редкоиспользуемых фич никого не беспокоит

НС>Авторов, вишь, таки беспокоит.
А я не про авторов, а про пользователей. Авторов оно беспокоит ровно по причине поддержки и портирования.
Re[24]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 30.06.14 08:44
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Далее смотрим в wiki: https://github.com/aspnet/EntityFramework/wiki/Getting-and-Building-the-Code

G>Выясняется что EF разрабатывается под K Runtime. который использует .NET Core Runtime (общий знаменатель для всех версий .NET)

Одновременно не означает в следствие.
Re[22]: Entity Framework за! и против!
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.06.14 08:46
Оценка:
Здравствуйте, IT, Вы писали:

IT>Давай пофиксим вместо. Давай пример неработающего кода, будем фиксить.


Будешь трогать генератор — посмотри на изменения в репозитории сайта, я там начал добавлять поддержку комментариев. Неплохо бы закинуть в реп linq2db.
AVK Blog
Re[23]: Entity Framework за! и против!
От: IB Австрия http://rsdn.ru
Дата: 30.06.14 09:02
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Докажи что именно это послужило причиной. Пока что твои заявления голословны.

Бесполезно. Он давно подсел на EF, а теперь просто обидно за зря потраченные годы... =) По человечески понятно, но это путь в никуда. Если уж разработчики сами явно пишут, что фигня получилась, а он рассказывает, что они имели ввиду что-то другое, то тут логика бессильна...
Мы уже победили, просто это еще не так заметно...
Re[25]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.06.14 10:47
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


G>>Далее смотрим в wiki: https://github.com/aspnet/EntityFramework/wiki/Getting-and-Building-the-Code

G>>Выясняется что EF разрабатывается под K Runtime. который использует .NET Core Runtime (общий знаменатель для всех версий .NET)

НС>Одновременно не означает в следствие.


Это ты о чем? Где там "одновременно" ???
Re[24]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.06.14 10:52
Оценка:
Здравствуйте, IB, Вы писали:

IB>Здравствуйте, Ночной Смотрящий, Вы писали:


НС>>Докажи что именно это послужило причиной. Пока что твои заявления голословны.

IB>Бесполезно. Он давно подсел на EF, а теперь просто обидно за зря потраченные годы... =) По человечески понятно, но это путь в никуда. Если уж разработчики сами явно пишут, что фигня получилась, а он рассказывает, что они имели ввиду что-то другое, то тут логика бессильна...

Вообще-то в том же пресс-релизе написано, который ты цитируешь. Я так понял что ты даже пресс-релизы невнимательно читаешь.

Насчет "путь в никуда" — очень даже ясно куда — EF7. Читаем пресс-релиз дальше:

Upgrade from EF6 to EF7 is a key scenario for us, both in terms of existing code and existing knowledge. We’ll be keeping the same concepts and patterns wherever it makes sense. The upgrade to EF7 will require some changes to your code. Our aim is that code that uses the core functionality of the DbContext API will upgrade easily, code that makes use of the lower level APIs in EF may require more complicated changes.


Но я понимаю что все факты расходятся с твоей верой, поэтому ты ищешь проблемы в других.
Re[19]: Entity Framework за! и против!
От: vdimas Россия  
Дата: 30.06.14 11:04
Оценка: :)
Здравствуйте, gandjustas, Вы писали:

V>>>>Такой ты наивный... А как же раньше подобные задачи решались? )))

G>>>Также как и сейчас «решают», делают малое количество запросов\процедур, покрывающих сценарии.

V>>"Мало" это сколько? Вот предположи, сколько суммарно на стороне базы сохраненных запросов и хранимок в средненькой системе, когда базу разрабатывают именно как базу, а не как "тупое хранилище объектов", где все запросы идут на LINQ? Почитав твои ответы ниже, я уверен, что ответ тебя удивит.

G>Я мигрировал небольшой проект на Linq, было 3-5 хранимок на таблицу для выборок, для таблиц с кучей колонок было побольше. После переписывания на Linq стало около 20 запросов на таблицу. Точной статистики, увы, не осталось.

Ну это что-то совсем простое. В тех проектах, где я участвовал и был выделенный программист БД, кол-во хранимок+сохраненных запросов было порядка 2к на примерно полторы-две сотни таблиц. И еще несколько десятков запросов составлялись динамически. Но эти "запросы" мы считали не по кол-ву результирующих сочетаний (а оно большое, ес-но, из-за комбинаторики условий), а по кол-ву таких параметризуемых "построителей". Т.е. динамических сценариев было довольно немного в общей куче.


G>>>Запросы не эффективны, тормозят, пинают их хинтами, чтобы работало приемлемо.

V>>Это LINQ генерит жутко неэффективные запросы.
G>Люди генерят неэффективные запросы, а Linq может косячить только в очень сложных случаях, которые вообще бессмысленно на Linq писать.

Linq использует далеко не все ср-ва языка. И речь не только о хинтах. Сам запрос в Linq формируется тупым переводом структуры исходного выражения. Поэтому, не спорь, Linq генерит заведомо плохой SQL "в лоб".


G>Вот мой личный хит-парад причин неэффективных запросов:

G>1) Отсутствие проекций. Люди не пишут select, это приводит к тому что тянется слишком много данных (особенно проблема для длинных строк и блобов) и не получается построить покрывающий индекс.

Куда тянется? Если это внутренний подзапрос, то ничего никуда не тянется.
Лишние поля на клиента мы не гоняли, ес-но, т.е. select самого верхнего уровня тщательный, ес-но. Мне даже трудно вообразить, где-то может быть не так и ты даже привел ЭТО как аргумент. ))


G>2) Люди пишут Linq запросы не понимая что происходит в базе. Особенно часто встречается FirstOrDefault, который в SQL работает очень медленно, или банально вызывают функции в предикатах.


Ну, если, действительно нужен First, то быстрее ты не сделаешь. А OrDefault можно и на клиентской стороне обыграть, но это не может существенно повлиять на результат. Что-то ты не то говоришь, кароч. Я тебе говорил о самом SQL. Кароч, оч большая разница с тем, какой SQL пишет специально-обученный и уже 20 лет этим занимающийся человек и SQL после Linq "обычного программиста". Это небо и земля.

Опять же. Есть такой фактор — владение проблемой. Когда программист SQL пишет запросы, он "видит" происходящую картинку. Именно так. Нет эдакого "разрыва" кода и базы. Просто индексы, статистику, материализцию view и прочее — такие решения принимает человек, который в этом "варится". А программист C# в этом не варится нифига, что бы кто не говорил.

G>3) Люди пытаются на Linq написать то, что в базе уже есть, но нет в Linq. Видел такие рукопашные реализации FTS и оператора Merge.


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

G>Я не знаю для чего по твоему нужны хинты, я видел как их применяют при использовании хранимок для Data Access.

Хинтами можно указать уровень блокировок. При частом обновлении это даёт прирост до нескольких раз, в особо клинических случаях — до порядка.

Ну и "длинные транзакции" всё-равно на стороне базы исполняются на многие порядки быстрее (с тащтельно подобранными уровнями блокировки), чем последовательность вызовов Linq с клиента базы в рамках одной транзакции. От этого ты вообще никак не убежишь.

Триггера те же и т.д.
Понимаешь, все эти триггера, длинные транзакции и прочее используют какую-то кодовую базу SQL, которая УЖЕ есть на стороне базы. Смысл её дублировать в Linq?

В этом смысле Linq можно рассматривать примерно как и весь дотнет — как неплохой тул для макетирования. А "взрослая" разработка все-равно перепишет львиную долю макета в "боевой" вид.

V>>Только не понятно, как ими пользоваться из LINQ? ))

G>Это показывает твой уровень знания SQL

Ты не показал, как этим пользоваться из Linq.

G>plan guide вообще-то есть.


Есть мильон служебных хелперов, и? Эти хелперы связаны с состоянием базы. Ты чуть подмандил свой запрос, и твой вызванный ранее plan guide стал бесполезен. Или ты каждый раз перед целевым запросом будешь настраивать plan guide?

Кароч, этот костыль не для этого сценария.

V>>>>Точно так же генерили SQL аж бегом.

G>>>Это только примитивные запросы, максимум джоины и простые предикаты, никаких группировок и подзапросов.

V>>Я вижу, ты страшно далек от понимания того, как подобные задачи решали и решают без LINQ. Обычно в тиме работает человек, специализирующийся на базах и запросах, он умеет SQL намного лучше, чем ты свой C# когда-либо умел или сумеешь. Ну и понимание происходящего в базе на порядки лучше твоего. Так бывает, когда человек многие годы на чём-то специализируется. )) Поэтому, твоя наивность опять зашкаливает. Если чего-то не знаешь — лучше спросить, ИМХО.

G>Я вообще-то занимаюсь обучением таких DBA и прекрасно осведомлен об их способностях.
G>Если есть отдельный DBA, который не лезет в код, и программисты, которые не лезут в базу, то получается impendance mismatch между людьми.
G>Если DBA "главнее" программистов, то он рисует базу, небольшой набор хранимок (большой поддерживать влом), запинывает их хинтами и грозится оторвать руки тем, кто фигачит Adhoc запросы в базу. При этом хранимок мало, они не отражают реальные потребности приложения и отдают зачастую слишком много данных, а программисты на стороне приложения сами разбираются.

Скорее, это результат ТВОЕГО обучения. )) А есть среди них те, кто хотя бы лет 15 именно этим занимается?

Про impendance mismatch я вообще молчу. С грамотным DBA я наблюдал ровно противоположное — у всех всё выспросит, заставить оформить требования, ни байта лишнего из базы не отдаст.

Про количество хранимок и вьюшек я написал выше. Я сразу в твоих аргументах ощутил специфический опыт, когда разработка на стороне базы фактически отсутствовала. ОК! В условиях объективной невозможности вести разработку на стороне базы, Linq тебе в помощь.

Правда, и до Linq был тот же Hibernate/NHibernate со своим построителем запросов. ))
Да и у нас в одном из проектов проекте был свой объектный построитель запросов, где тоже шла комбинация условий, в т.ч. групповые операции и затем сериализация в SQL. Но я прекрасно помню, для каких именно сценариев мы такое делали — для динамики, для вычурной аналитики, вызываемой клиентами из специальных форм и отчетов. А такие сценарии — капля в море в общей "боевой" нагрузке.

G>Если же программисты "главнее" DBA, то программисты юзают базу как тупое хранилище объектов, а DBA только пишет batch processing для самых тормозящих сценариев.


И этот подход прекрасно работает, пока в таблицах сотни тыщ / единицы мильонов строк! )))

Кароч, пока SQL-сервак в состоянии держать все частоисопльзуемые индексы и даже данные в оперативной памяти, всё прекрасно работает хоть на Linq, хоть на коленке. Но для таких сценариев не всегда реляционная база — лучший вариант. Объектные или blob-базы могуть зарулить всё и вся. Когда идет обработка "просто графов объектов" в памяти, то там реляционки сливают на порядок и больше, бо они изначально нужны для медленных внешних хранилищ и ни для чего более.


G>Лет 7-8 назад такое было повсеместно, потом появился Linq и больше C# программистов стало понимать что происходит в базе и как сделать оптимальной работу с СУБД.

G>Но тебя это, видимо не коснулось. Не беспокойся, еще не поздно изучить.

Что ИМЕННО надо изучить?
И КАК C#-программист начнет понимать происходящее в базе, особенно, если разные программисты разрабатывают разные абстрактные предикаты, из которых собирается целевой запрос "кем-то еще"? Даже по неизвестной заранее таблице? Как преодолеть ту пропасть между мышлением "типами" у программиста и "доменами" у DBA? )) Я вживую такое не видел и тебе не верю — бо помню тебя по прошлым обсуждениям. Слишком большая косность мышления у фанатов "dotnet only", что даже с прочтением IL-кода были неразрешимые трудности. Мышление в типах — это "плоское" 2D-мышление. Во главе угла — простота. ))) В доменах — объемное, пространственное мышление. Точнее — многомерное. Умение держать в голове слишком много сразу, чтобы уметь принимать адекватные решения. Редкие люди хорошо умеют и то и другое, тут нужна определённая гибкость ума, умение быстро перестраиваться, которое мало кто здесь демонстрирует. А если у кого настолько светлая и гибкая голова, то тратить её на тупую инженерию, типа прикладника на C# или SQL было не иначе как преступлением. Хотя, есть здесь и единицы таких. ))


G>>>Добавляй сразу в классы, ef добавит его в базу.


V>>Не со всеми нужными св-вами. Не со всеми связями, ограничениями, триггерами и т.д. до бесконечности. Как-то ты примитивно рассматриваешь базу, однако.

G>Так добавь что нужно, тебя никто не ограничивает.

Добавлю, конечно. Иначе бы не приводил как аргумент того, что от независимого изменения базы ты не убежишь. Этот "автоматизм" вообще малость опасен. Возьмет какой-нить программист удалит поле, синхронизирует, потом обнаружит, что оно было нужно таки, быстро добавит обратно, опять синхронизирует. И тю-тю все прежние настройки. Если диффы по SQL-определениям таблиц не вести, то и не заметишь ничего. А их удобнее вести именно при полноценной разработки базы со стороны базы.


V>>Согласен только насчет последнего, но это извращение, а не аргумент в споре. Динамические, как раз, можно построить "извне" базы и так часто и делают. Но я утверждаю, что таких запросов (динамических по своей структуре, а не по простым параметрам) менее 10% от обслуживаемых средней базой в течении суток, скажем. А то и менее 1%, положа руку на.

G>Не пойму что ты сказать хочешь. Количество запросов, генерируемых программой — конечно (без учета параметров), кеш планов SQL Server на этот факт и рассчитан.
G>Например у тебя в программе есть Grid, который позволяет фильтровать и сортировать по любой колонке (как excel). Количество разных (без учета параметризации) запросов будет очень большим (порядка 2n*2^n!, где n — кол-во колонок), но конечным. При этом если грид на главной странице приложения, то на эти динамические запросы будет приходится большая часть запросов. Или это по твоему не динамические запросы?

Ох, блин. Ну ты дал!
Нет, не динамические. Подготавливается заранее view, скрывающий всю сложность низлежащего запроса, а уже на результат можно накладывать сортировку и фильтрацию. View делается DBA, конкретный тупой SQL-запрос к этому view пишет программист. Но он же тривиальный, много ума не надо, бо по специально заточенному view идёт тупой "select * from ... where ... order by ...".


G>Что ты имеешь ввиду под динамическими запросами?


С динамической структурой, затрагивающей подзапросы. Т.е. где в условиях идут еще выборки или групповые операции над ними, типа exists, any и т.д. из этой оперы. С перекрестными связями по-условию м/у подуровнями — прикольнее всего. ))


V>>Это обычно только какие-нить специфические отчеты, редко потребляемая аналитика или что-то в этом роде. Я не спорю, что таких запросов может быть абсолютное большинство, если считать запросы не в кол-ве реальных употреблений, а в штуках наличия самих запросов.

G>Как раз для отчетов запросы статичны, то есть они один раз задаются и много раз вызываются.

Это список полей статичный, а запрос к базе может быть очень даже динамичным в том смысле, что я написал выше.

Простой пример — список товаров со склада, краткая форма. Вид отчета одинаков для любых выборок, но самих выборок — масса. Простая выборка, для которой цена отпуска товара отличается от средней более чем на 15% (за некий период) уже требует подзапросов. А если товары еще дополнительно делятся по "разносортице" (в стандартной 1С не поддерживается, почему до сих пор полно самописных складских программ со своими прибамбасами), то это будет запрос с 3-мя и более "уровнями", со ссылками на первый уровень из самого низа.

V>>Но это маргинальный, по-сути, сценарий, на который, как раз LINQ прекрасно ложится. Т.е. LINQ хорош в процессе построения нетривиальных, динамических запросов, угу. Но это же development time для 90-99% реальных случаев. Зачем же снова и снова строить одни и те же запросы в рантайм? )))

G>У тебя каша в голове.

А ну да. Я помню про "гибкость". ))

G>Давай по порядку: что ты называешь динамическими запросами?


Ну я заведомо исключил из них те, где меняются простые параметры, бо для ТАКИХ сценариев вообще Linq не облокотился и обсуждать сразу нечего.
Я рассматриваю те сценарии, где Linq еще хоть зачем-то нужен, например, если ты заранее не знаешь, какой будет конечный join.


G>Я грешным делом подумал что называешь динамическими запросы, которые клеятся по кускам, но прочитав твой ответ я понял, что не понял что ты называешь динамическими запросами.


Это запросы с неизвестной заранее структурой и уровнями вложенности. Например, в одной из систем был способ визуального построения иерархического фильтра и простенький DSL к нему, для пользования клиентами.
Re[19]: Entity Framework за! и против!
От: vdimas Россия  
Дата: 30.06.14 11:17
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:


НС>Да ничего неожиданного. Можно, к примеру, так:

НС>
НС>db
НС>    .Messages
НС>    .WithIndex(Message.IDIndex)
НС>    .Select(m => m.ID)
НС>    .Option(SqlOption.HashGroup)
НС>    .Option(SqlOption.Fast, 10);
НС>

НС>Хинты и LINQ, в общем случае, перпендикулярны.

А в синтаксисе именно LINQ?

Так-то у нас "объектный" построитель запросов в похожем синтаксисе (построенный на тогдашнем BLT, кста) был еще в 2004-м, Linq не нужен?)))


V>>Я вижу, ты страшно далек от понимания того, как подобные задачи решали и решают без LINQ. Обычно в тиме работает человек, специализирующийся на базах и запросах, он умеет SQL намного лучше, чем ты свой C# когда-либо умел или сумеешь.

НС>Ага, а потом я в таких проектах переписываю хранимки на linq2db и получаю ускорение в 2-3 раза.

За счет чего именно?
Чудес же не бывает, правильно?
Я бы мог ответить "это твой опыт, такой у вас был ДВА и т.д.", но вижу подобный аргумент уже не первый раз. Хочу понять, мож что-то фундаментальное там?

Тем более, что самые "тяжелые" хранимки (по моему субъективному опыту) ни на какой Linq не перенесешь, бо там несколько операций с промежуточными таблицами, обычно, т.е. "длинные транзакции", которые на стороне базы примерно на пару порядков быстрее, чем точно такая же последовательность операций в "длинной транзакции" со стороны клиента.


V>>Зачем же снова и снова строить одни и те же запросы в рантайм? )))

НС>Нормальные linq провайдеры умеют запросы кешировать.

Речь об общей кодовой базе. Повторного использования кода на стороне БД, при разработке именно со стороны БД оч много. Часто одни view строятся на основе других, точно так же sp и табличные ф-ии. Т.е. как в обычном программировании, есть "низкоуровневый" и "высокоуровневый" слой. А это уже кеширование на стороне базы, что совсем другое дело, чем кеширование текста на стороне клиента. (Я не считаю клиентские затраты на генерирование тескта SQL существенными, т.е. речь не об этом).
Re[19]: Entity Framework за! и против!
От: vdimas Россия  
Дата: 30.06.14 11:41
Оценка:
Здравствуйте, IT, Вы писали:

IT> Т.е. начинаю я работать над какой-нибудь формой и мне нужно заполнить её данными, пока двумя полями. Я зову Васю-Специалиста-На-Базах-И-Запросах и он пишет мне в моём коде SQL, который читает эти два поля для меня из базы. Через 10 минут мне надо подчитать третье поле,


Т.е. ты сам себе ПМ, аналитик, архитектор и тот самый Вася, если тебе через 10 мин (!!!) потребовалось третье поле. ))

Такого рода задачи у нас тоже бывали, но ничего серьезного обычно, т.е. проекты сами несерьезные, обсуждать бессмысленно. Из подобного наколенного творчества делать какие-либо выводы я бы не стал, хотя сам именно в таком режиме много чего понаделал.


IT>я опять зову Васю-Специалиста-На-Базах-И-Запросах и он мне дописывает SQL по требованию. Потом мне нужно будет добавить четвёртое поле, сделать группировку, чего-нибудь отфильтровать и каждый раз мне нужно будет звать Васю-Специалиста-На-Базах-И-Запросах. Тебе самому не смешно?


Нисколько. Я уже не первый год говорю, что дотнет и Linq являются неплохими инструментами для прототипирования. Сейчас даже архитекторы, вместо контруирования форм в "специальных" программах, накидывают их прямо в студии и общаются потом с клиентами.

Дай-ка угадаю, чтобы мы этот твой аргумент (уже не первый раз тобой приведенный за последние годы, кста), "проехали", наконец.
Ты плотно работаешь в команде не более 3-х человек?
Т.е. независимо от кол-ва людей в конторе, плотно по работе у тебя максимум пара коллег контактирует в каждом проекте. Другая организация труда тебе будет просто раздражать, ты работать по-другому не будешь и продуктивно не сможешь при всем желании.


V>>он умеет SQL намного лучше, чем ты свой C# когда-либо умел или сумеешь.

IT>Хорошее знание SQL — это обязательный скил для разработчика среднего уровня.

Речь была о специфике конкретной БД. Иначе зачем нам ДБ-разраб, когда дело касалось бы "голого SQL"?


IT>Глубокая специализация имеет две стороны. Положительную — хорошее знание в специализирующейся области. Отрицательную — костность мышления и неприятие любых других технологий.


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

Косность мышления — это почти врожденное кач-во человека (наполовину врожденное, если быть точным — только по координате сенсорик/интуит), от глубины специализации сие никак не зависит. Обычно к косности склонны сенсорики-интроверты (дотошность, конкретное мышление), на другом полюсе находятся интуиты-экстраверты (экспериментаторы и аналитики по-натуре, склонные к абстрактному мышлению). Кароч, речь идет о т.н. "гибкости ума". Гибкость ума ну никак не может мешать глубокой специализации в чем-либо, хотя да, вторая упомянутая группа склонна к поверхностности... но тут дело сугубо специфичное у каждого человка. Мы же говорим о спецах, так? Так вот, ровно наоборот, без достаточной гибкости ума сию глубину-то и не достигнешь, бо на каждом уровне понимания области собственной деятельности часто открываются совсем разные по характеру задачи и ньюансы. Поэтому даже во второй группе технических спецов (именно глубоких спецов своего дела) встречается намного больше, чем в первой. Из первой прут руководители, филологи, историки и т.д., из второй — ученые и артисты. ))


IT>Худшие архитектурные решение, которые мне доводилось видеть в своей жизни были сделаны людьми, специализирующимися на базах и запросах. Т.к. кроме этого они толком ничего не умееют и не хотят уметь. База данных, это важная, но всё же часть любого приложения, а для них она почему-то всегда не просто часть, а единственная часть приложения. В результате всё остальное приносится в жертву и получается очередное гипертрофированное в сторону БД уродство.


А я видел худшие архитектурные решения от "программистов от сохи", и?

Худшие архитектурные решения получаются у людей, чей кредит доверия превышает их профессиональные навыки, а всё остальное — лирика и субъективизм. Я наблюдал, что тот же самый человек, но уже с адекватным кредитом доверия, порождает потом неплохие в итоге решения, потому что из работы выключен банальный личный снобизм. Человек был ВЫНУЖДЕН быть открытым и любопытным. Что дало требуемые плоды. Всё-таки все плохие решения идут обычно от недостатка информации и ни от чего более. (Малый опыт я не рассматриваю, бо бесполезно в этом споре)
Re[20]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 30.06.14 12:42
Оценка: +1
Здравствуйте, vdimas, Вы писали:

НС>>Хинты и LINQ, в общем случае, перпендикулярны.

V>А в синтаксисе именно LINQ?

Сто такое "синтаксис LINQ"? Если ты про query comprehension, то это не обязательная и даже не основная его часть. Я, к примеру, ей вообще не пользуюсь.

V>Так-то у нас "объектный" построитель запросов в похожем синтаксисе


Похожесть тебе только показалась. Ключевой момент здесь — наличие expression tree, которого в 2004 не было. А QC это так, мелочевка.

НС>>Ага, а потом я в таких проектах переписываю хранимки на linq2db и получаю ускорение в 2-3 раза.

V>За счет чего именно?

За счет того что выкидывается куча странного кода внутри хранимок. Особо весело выходит, когда одна хранимка вызывает другую, та третью и т.д.

V>Я бы мог ответить "это твой опыт, такой у вас был ДВА и т.д."


Проблема только в том, что я в куче проектов такое видел. А, судя по общению с коллегами, не только я.

V>Тем более, что самые "тяжелые" хранимки (по моему субъективному опыту) ни на какой Linq не перенесешь, бо там несколько операций с промежуточными таблицами, обычно


Во-во, навертят бреда вокруг промежуточных таблиц на ровном месте с десятком select into, а потом оказывается что все можно переписать без них.

V>>>Зачем же снова и снова строить одни и те же запросы в рантайм? )))

НС>>Нормальные linq провайдеры умеют запросы кешировать.
V>Речь об общей кодовой базе. Повторного использования кода на стороне БД, при разработке именно со стороны БД оч много.

Моя практика в рамках нескольких разнородных проектов показывает наоборот, такого кода очень мало. 90% запросов уникальны.
Re[20]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.06.14 12:51
Оценка: +1
Здравствуйте, vdimas, Вы писали:

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


V>>>>>Такой ты наивный... А как же раньше подобные задачи решались? )))

G>>>>Также как и сейчас «решают», делают малое количество запросов\процедур, покрывающих сценарии.

V>>>"Мало" это сколько? Вот предположи, сколько суммарно на стороне базы сохраненных запросов и хранимок в средненькой системе, когда базу разрабатывают именно как базу, а не как "тупое хранилище объектов", где все запросы идут на LINQ? Почитав твои ответы ниже, я уверен, что ответ тебя удивит.

G>>Я мигрировал небольшой проект на Linq, было 3-5 хранимок на таблицу для выборок, для таблиц с кучей колонок было побольше. После переписывания на Linq стало около 20 запросов на таблицу. Точной статистики, увы, не осталось.

V>Ну это что-то совсем простое. В тех проектах, где я участвовал и был выделенный программист БД, кол-во хранимок+сохраненных запросов было порядка 2к на примерно полторы-две сотни таблиц. И еще несколько десятков запросов составлялись динамически. Но эти "запросы" мы считали не по кол-ву результирующих сочетаний (а оно большое, ес-но, из-за комбинаторики условий), а по кол-ву таких параметризуемых "построителей". Т.е. динамических сценариев было довольно немного в общей куче.

Я тоже видел такие проекты, но там по факту половина хранимок не использовалось, добавление поля это была задача примерно на месяц. Проект очень быстро загнулся.
Даже банальная математика говорит что при 2к хранимок и 200 таблиц это минимум 10 хранимок на таблицу, а скорее всего в два раза больше. Любая правка в исходной таблице — нужна синхронная правка около 20 хранимок. Команда из 3-4 программистов будет поля править раз в день, DBA от такого сдохнет.
При этом Linq позволяет генерировать больше и более специализированные запросы, чем выделенный DBA.


G>>>>Запросы не эффективны, тормозят, пинают их хинтами, чтобы работало приемлемо.

V>>>Это LINQ генерит жутко неэффективные запросы.
G>>Люди генерят неэффективные запросы, а Linq может косячить только в очень сложных случаях, которые вообще бессмысленно на Linq писать.
V>Linq использует далеко не все ср-ва языка. И речь не только о хинтах. Сам запрос в Linq формируется тупым переводом структуры исходного выражения. Поэтому, не спорь, Linq генерит заведомо плохой SQL "в лоб".
Уж прости, но аргументация на уровне детского сада.

Linq умеет генерить:
1) все виды джоинов
2) подзапросы
3) группировки
4) предикаты
Этого хватает чтобы покрыть 99% запросов.

Linq не умеет (зависит от провайдера):
1) CTE
2) merge operator
3) ranking-функции
Сколько запросов у тебя содержат эти функции?

Что ты считаешь "плохим" SQL и почему Linq его генерит сам?



G>>Вот мой личный хит-парад причин неэффективных запросов:

G>>1) Отсутствие проекций. Люди не пишут select, это приводит к тому что тянется слишком много данных (особенно проблема для длинных строк и блобов) и не получается построить покрывающий индекс.

V>Куда тянется? Если это внутренний подзапрос, то ничего никуда не тянется.

С чего ты взял? От проекции в запросе (неважно подзапрос это или нет) зависит какой план построит SQL, а это напрямую влияет на быстродействие. Конечно кроме случаев, когда ты используешь подзапрос в exists выражении.

V>Лишние поля на клиента мы не гоняли, ес-но, т.е. select самого верхнего уровня тщательный, ес-но. Мне даже трудно вообразить, где-то может быть не так и ты даже привел ЭТО как аргумент. ))

Знал бы ты сколько я таких запросов починил... Не хватит пальцев рук у всех родственников до третьего колена.


G>>2) Люди пишут Linq запросы не понимая что происходит в базе. Особенно часто встречается FirstOrDefault, который в SQL работает очень медленно, или банально вызывают функции в предикатах.


V>Ну, если, действительно нужен First, то быстрее ты не сделаешь. А OrDefault можно и на клиентской стороне обыграть, но это не может существенно повлиять на результат. Что-то ты не то говоришь, кароч. Я тебе говорил о самом SQL. Кароч, оч большая разница с тем, какой SQL пишет специально-обученный и уже 20 лет этим занимающийся человек и SQL после Linq "обычного программиста". Это небо и земля.

Разница конечно есть, но не всегда в положительную сторону. Человек может ошибаться или банально не знать о конкретных потребностях приложения, поэтому делать неоптимальные запросы.

V>Опять же. Есть такой фактор — владение проблемой. Когда программист SQL пишет запросы, он "видит" происходящую картинку. Именно так. Нет эдакого "разрыва" кода и базы. Просто индексы, статистику, материализцию view и прочее — такие решения принимает человек, который в этом "варится". А программист C# в этом не варится нифига, что бы кто не говорил.

Проблема в том, что "картинка" которую он "видит" может с реальным потребностями и проблемами расходиться. Именно так часто и получается.

G>>3) Люди пытаются на Linq написать то, что в базе уже есть, но нет в Linq. Видел такие рукопашные реализации FTS и оператора Merge.


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

G>>Я не знаю для чего по твоему нужны хинты, я видел как их применяют при использовании хранимок для Data Access.
V>Хинтами можно указать уровень блокировок. При частом обновлении это даёт прирост до нескольких раз, в особо клинических случаях — до порядка.
Особо клинические случаи получаются как раз по причинам, описанным выше.

EF кстати генрит базы с READ_COMMITED_SNAPSHOT, так что блокировки, скорее всего, не станут проблемой.

V>Ну и "длинные транзакции" всё-равно на стороне базы исполняются на многие порядки быстрее (с тащтельно подобранными уровнями блокировки), чем последовательность вызовов Linq с клиента базы в рамках одной транзакции. От этого ты вообще никак не убежишь.

"Длинные транзакции" это что? Если у тебя один селект работает полчаса это длинная транзакция? А 1000 инсертов за секунду, отправленных одним батчем? И то и другое вполне может быть сделано как Linq, так и написано вручную.

V>Триггера те же и т.д.

V>Понимаешь, все эти триггера, длинные транзакции и прочее используют какую-то кодовую базу SQL, которая УЖЕ есть на стороне базы. Смысл её дублировать в Linq?
А кто говорит что надо дублировать? Типичное распределение чтения\записи в веб-приложении — 98\2. Об оптимизации записи речи в этом плане не идет.

V>В этом смысле Linq можно рассматривать примерно как и весь дотнет — как неплохой тул для макетирования. А "взрослая" разработка все-равно перепишет львиную долю макета в "боевой" вид.

Ну вот сайт сочи 2014 собрали макет и он удачно проработал...

V>>>Только не понятно, как ими пользоваться из LINQ? ))

G>>Это показывает твой уровень знания SQL
V>Ты не показал, как этим пользоваться из Linq.
Хинты в частности и любая оптимизация вообще должна выполняться как раз знающим человеком, поэтому допускать писать хинты в Linq категорически нельзя, ибо программисты хинтами зафиксируют план, потому что им покажется что "так лучше" и оптимизировать станет возможно только путем изменения кода. Поэтому хинты только через план-гайды.

G>>plan guide вообще-то есть.

V>Есть мильон служебных хелперов, и? Эти хелперы связаны с состоянием базы. Ты чуть подмандил свой запрос, и твой вызванный ранее plan guide стал бесполезен. Или ты каждый раз перед целевым запросом будешь настраивать plan guide?
План-гайд или хинты для каждого запроса — индикатор неграмотного DBA. В базе много средств построения оптимальных планов без хинтов. Увы не все это знают. linq в этом плане помогает, ибо не дает писать хинты.


G>>Я вообще-то занимаюсь обучением таких DBA и прекрасно осведомлен об их способностях.

G>>Если есть отдельный DBA, который не лезет в код, и программисты, которые не лезут в базу, то получается impendance mismatch между людьми.
G>>Если DBA "главнее" программистов, то он рисует базу, небольшой набор хранимок (большой поддерживать влом), запинывает их хинтами и грозится оторвать руки тем, кто фигачит Adhoc запросы в базу. При этом хранимок мало, они не отражают реальные потребности приложения и отдают зачастую слишком много данных, а программисты на стороне приложения сами разбираются.

V>Скорее, это результат ТВОЕГО обучения. )) А есть среди них те, кто хотя бы лет 15 именно этим занимается?

нет, это состояние ДО обучения. Был один раз DBA с огромным опытом, чуть ли не 20 лет, имел должность "главного архитектора". С удивлением узнал про read_commited_snapshot и не очень понимал как работает статистика.

V>Про impendance mismatch я вообще молчу. С грамотным DBA я наблюдал ровно противоположное — у всех всё выспросит, заставить оформить требования, ни байта лишнего из базы не отдаст.

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

V>Про количество хранимок и вьюшек я написал выше. Я сразу в твоих аргументах ощутил специфический опыт, когда разработка на стороне базы фактически отсутствовала. ОК! В условиях объективной невозможности вести разработку на стороне базы, Linq тебе в помощь.

С чего ты взял что отсутствовала? Я говорил именно про запросы, которые идут от приложения в базу. То что происходит внутри базы не является предметом разговора.

V>Правда, и до Linq был тот же Hibernate/NHibernate со своим построителем запросов. ))

там постритель запросов с трудом осиливает джоины и предикаты. Подзапросы и проекции — жопа.

G>>Если же программисты "главнее" DBA, то программисты юзают базу как тупое хранилище объектов, а DBA только пишет batch processing для самых тормозящих сценариев.

V>И этот подход прекрасно работает, пока в таблицах сотни тыщ / единицы мильонов строк! )))
Ну это ели не сделать чтонить типа select N+1. Посадить производительность можно всегда, и даже Linq в этом не помешает.


G>>Лет 7-8 назад такое было повсеместно, потом появился Linq и больше C# программистов стало понимать что происходит в базе и как сделать оптимальной работу с СУБД.

G>>Но тебя это, видимо не коснулось. Не беспокойся, еще не поздно изучить.

V>Что ИМЕННО надо изучить?

Как работает SQL.

V>И КАК C#-программист начнет понимать происходящее в базе, особенно, если разные программисты разрабатывают разные абстрактные предикаты, из которых собирается целевой запрос "кем-то еще"? Даже по неизвестной заранее таблице? Как преодолеть ту пропасть между мышлением "типами" у программиста и "доменами" у DBA? ))

Изучать и SQL, и C#.

G>>>>Добавляй сразу в классы, ef добавит его в базу.


V>>>Не со всеми нужными св-вами. Не со всеми связями, ограничениями, триггерами и т.д. до бесконечности. Как-то ты примитивно рассматриваешь базу, однако.

G>>Так добавь что нужно, тебя никто не ограничивает.

V>Добавлю, конечно. Иначе бы не приводил как аргумент того, что от независимого изменения базы ты не убежишь. Этот "автоматизм" вообще малость опасен. Возьмет какой-нить программист удалит поле, синхронизирует, потом обнаружит, что оно было нужно таки, быстро добавит обратно, опять синхронизирует. И тю-тю все прежние настройки. Если диффы по SQL-определениям таблиц не вести, то и не заметишь ничего. А их удобнее вести именно при полноценной разработки базы со стороны базы.

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



V>Нет, не динамические. Подготавливается заранее view, скрывающий всю сложность низлежащего запроса, а уже на результат можно накладывать сортировку и фильтрацию. View делается DBA, конкретный тупой SQL-запрос к этому view пишет программист. Но он же тривиальный, много ума не надо, бо по специально заточенному view идёт тупой "select * from ... where ... order by ...".


так where и orderby каждый раз будут разными, это все равно не динамический запрос?


G>>Что ты имеешь ввиду под динамическими запросами?


V>С динамической структурой, затрагивающей подзапросы. Т.е. где в условиях идут еще выборки или групповые операции над ними, типа exists, any и т.д. из этой оперы. С перекрестными связями по-условию м/у подуровнями — прикольнее всего. ))

А чем такие запросы в принципе отличаются от "select * from .. where ..." где предикаты формируются в UI (с точки зрения SQL)?


V>>>Это обычно только какие-нить специфические отчеты, редко потребляемая аналитика или что-то в этом роде. Я не спорю, что таких запросов может быть абсолютное большинство, если считать запросы не в кол-ве реальных употреблений, а в штуках наличия самих запросов.

G>>Как раз для отчетов запросы статичны, то есть они один раз задаются и много раз вызываются.
V>Это список полей статичный, а запрос к базе может быть очень даже динамичным в том смысле, что я написал выше.
Увы, не могу понять твое определение динамичности. Для SQL это такой же запрос.


G>>Давай по порядку: что ты называешь динамическими запросами?


V>Ну я заведомо исключил из них те, где меняются простые параметры, бо для ТАКИХ сценариев вообще Linq не облокотился и обсуждать сразу нечего.

V>Я рассматриваю те сценарии, где Linq еще хоть зачем-то нужен, например, если ты заранее не знаешь, какой будет конечный join.
Что значит "заранее не знаешь" ?


G>>Я грешным делом подумал что называешь динамическими запросы, которые клеятся по кускам, но прочитав твой ответ я понял, что не понял что ты называешь динамическими запросами.

V>Это запросы с неизвестной заранее структурой и уровнями вложенности. Например, в одной из систем был способ визуального построения иерархического фильтра и простенький DSL к нему, для пользования клиентами.
И что? Он все равно давал на выходе конечное множество запросов. Чем такая штука принципиально отличается от грида с настраиваемыми сортировками? (опять же с точки зрения SQL).
Re[20]: Entity Framework за! и против!
От: Ночной Смотрящий Россия  
Дата: 30.06.14 12:54
Оценка: :)
Здравствуйте, vdimas, Вы писали:

V>Сам запрос в Linq формируется тупым переводом структуры исходного выражения.


Лучше не пиши того, о чем не знаешь. Даже если никаких оптимизаций не делать тупой перевод LINQ в SQL все равно невозможен, там разная структура запросов и разные языковые возможности. IT тут не зря написал, что собственный linq провайдер это очень сложно и дорого.
Вообще, читая тут твои сообщения складывается стойкое ощущение, что в твоем представлении LINQ это просто встроенный в C# SQL.
Re[20]: Entity Framework за! и против!
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.06.14 14:37
Оценка: :)
Здравствуйте, vdimas, Вы писали:

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


IT>> Т.е. начинаю я работать над какой-нибудь формой и мне нужно заполнить её данными, пока двумя полями. Я зову Васю-Специалиста-На-Базах-И-Запросах и он пишет мне в моём коде SQL, который читает эти два поля для меня из базы. Через 10 минут мне надо подчитать третье поле,


V>Т.е. ты сам себе ПМ, аналитик, архитектор и тот самый Вася, если тебе через 10 мин (!!!) потребовалось третье поле. ))


Как это связано? Чтобы добавить поле нужен аналитик, архитектор и еще кто-то?

V>Худшие архитектурные решения получаются у людей, чей кредит доверия превышает их профессиональные навыки, а всё остальное — лирика и субъективизм.


На поле СУБД часто наблюдаются искажения. Человек знающий слово "статистика", "хинт" или "покрывающий индекс" получает практически неограниченный кредит доверия со стороны тех, кто подобных слов не знает.

Причем если бы вместо СУБД был функциональный язык, то его бы послали и запилили все на "родном" C#\Java\PHP. Но СУБД такая штука, что отказаться от неё нельзя, а вникать как она работает всем не хочется (выводит из зоны комфорта).
Вот и получается, что DBA с посредственными навыками получают слишком большой кредит доверия.

Кстати по этой же причине последние годы появилось повальное увлечение NoSQL базами. Они банально проще и работа с ними более прямолинейна.
Re[21]: Entity Framework за! и против!
От: vdimas Россия  
Дата: 30.06.14 14:43
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Даже банальная математика говорит что при 2к хранимок и 200 таблиц это минимум 10 хранимок на таблицу, а скорее всего в два раза больше. Любая правка в исходной таблице — нужна синхронная правка около 20 хранимок. Команда из 3-4 программистов будет поля править раз в день, DBA от такого сдохнет.


Во-во, и после этого ты еще поучаешь коллег.
Все запросы всей базы верифицируются после изменений.

G>При этом Linq позволяет генерировать больше и более специализированные запросы, чем выделенный DBA.


Ты плохо представляешь себе работу DBA. В 90% случаев от "слепит" тебе результат из уже готовых view, табличных ф-ий или уже готовых SP. У грамотного разработчика большое повторное использование кода. Соответственно его вариант будет намного-намного проще твоего, построенного на Linq с 0-ля.

G>>>>>Запросы не эффективны, тормозят, пинают их хинтами, чтобы работало приемлемо.

V>>>>Это LINQ генерит жутко неэффективные запросы.
G>>>Люди генерят неэффективные запросы, а Linq может косячить только в очень сложных случаях, которые вообще бессмысленно на Linq писать.
V>>Linq использует далеко не все ср-ва языка. И речь не только о хинтах. Сам запрос в Linq формируется тупым переводом структуры исходного выражения. Поэтому, не спорь, Linq генерит заведомо плохой SQL "в лоб".
G>Уж прости, но аргументация на уровне детского сада.

Нормальная аргументация.

G>Linq умеет генерить:

G>1) все виды джоинов
G>2) подзапросы
G>3) группировки
G>4) предикаты
G>Этого хватает чтобы покрыть 99% запросов.

Кто же спорит...
Я говорил про вид запросов. Одно и тоже сложное выражение можно вертеть многими способами. На Linq это банально неудобно, т.к. не очевидно. Например, очередность и взаимная вложенность подзапросов запросто может зависеть от конкретного провайдера, порождающего код SQL.

А рассуждения из цикла "MS SQL умный и сам составит нужный план" — и есть детсад. Это только на относительно несложных запросах. Вложи 3 раза exists/any друг в друга и получишь, что вертя внешней формой одного и того же запроса будешь менять конечный план.


G>Linq не умеет (зависит от провайдера):

G>1) CTE
G>2) merge operator
G>3) ranking-функции
G>Сколько запросов у тебя содержат эти функции?

С любыми запросами на групповое обновление — беда. А их бывает дохрена в учетных системах. Linq тебе поможет в обновлении только пообъектно, то бишь построчно. Хаха, как грится.


G>Что ты считаешь "плохим" SQL и почему Linq его генерит сам?


Потому что программист борется за лучшую читабельность, вестимо. Это же на уровне мозжечка, на то он и программист. А по закону подлости, наилучшим образом читаемый Linq-запрос не всегда самый лучший.

V>>Куда тянется? Если это внутренний подзапрос, то ничего никуда не тянется.

G>С чего ты взял? От проекции в запросе (неважно подзапрос это или нет) зависит какой план построит SQL, а это напрямую влияет на быстродействие. Конечно кроме случаев, когда ты используешь подзапрос в exists выражении.

Да любой подзапрос, если его поля используются только для построения условий на других уровнях — там вовсе не надо указывать никакие проекции, "унутре" всегда читается строка в ОП целиком (кроме тех самых блобов и text), бо MS SQL хранит построчно.


V>>Лишние поля на клиента мы не гоняли, ес-но, т.е. select самого верхнего уровня тщательный, ес-но. Мне даже трудно вообразить, где-то может быть не так и ты даже привел ЭТО как аргумент. ))

G>Знал бы ты сколько я таких запросов починил... Не хватит пальцев рук у всех родственников до третьего колена.

Мде. Теперь я знаю, чем еще плох Linq. )))
Шутю. Вряд ли буду использовать сие как аргумент конкретно по Linq, т.к. не вооруженным взглядом видно, что тут речь об уровне разработчика скорее, т.е. это будет чистой воды спекуляция. Ну и ты, ес-но, такой мощный разработчик, подбираешь за другими их г-но... Если бы я всё то г-но, что подбирал за неопытными коллегами, приводил как аргумент, спорить можно было бы бесконечно и ни о чем в то же время. ))


G>>>2) Люди пишут Linq запросы не понимая что происходит в базе. Особенно часто встречается FirstOrDefault, который в SQL работает очень медленно, или банально вызывают функции в предикатах.


V>>Ну, если, действительно нужен First, то быстрее ты не сделаешь. А OrDefault можно и на клиентской стороне обыграть, но это не может существенно повлиять на результат. Что-то ты не то говоришь, кароч. Я тебе говорил о самом SQL. Кароч, оч большая разница с тем, какой SQL пишет специально-обученный и уже 20 лет этим занимающийся человек и SQL после Linq "обычного программиста". Это небо и земля.


G>Разница конечно есть, но не всегда в положительную сторону. Человек может ошибаться или банально не знать о конкретных потребностях приложения, поэтому делать неоптимальные запросы.


Да ХЗ.
Я привел такой аргумент как "вариться" во всём этом. Пытаться его раскрыть можно долго и нудно, но мне банально облом. Когда ты "варишься" в чем-то, то у тебя совсем другие навыки, чем у того, который делает это лишь "мимоходом". Другие сценарии, ты в другие места смотришь, когда видишь результат и т.д. DBA следит не за приложением, в отличие от программиста, а за данными. И эти данные на одном и том же приложении могут быть разные у разных влиентов. Поэтому и индексы и прикручиваемые хинты могут быть разные.

Да. Серьезные приложухи на стороне базы — это ад для современных программистов. Это и так известно. Но выхода не было, по тем ресурсам аппаратуры, что были еще до времен MS SQL 2005. Сейчас то же самое с той лишь разницей, что эта граница отодвинулась примерно в 5 раз. Но она не исчезла. Просто да, многие нагрузочные раньше приложения стали простыми с т.з. требуемой мощности. Но далеко не все. Серьезные по размерам базы всё так же обслуживаются DBA по-старинке, я знаю это их первых рук, как грится.

А простые сценарии обсуждать облом. Я уже высказывался про то, что когда вся база влезает в оперативку сервака, то реляционка является заведомо худшим выбором.

V>>Опять же. Есть такой фактор — владение проблемой. Когда программист SQL пишет запросы, он "видит" происходящую картинку. Именно так. Нет эдакого "разрыва" кода и базы. Просто индексы, статистику, материализцию view и прочее — такие решения принимает человек, который в этом "варится". А программист C# в этом не варится нифига, что бы кто не говорил.

G>Проблема в том, что "картинка" которую он "видит" может с реальным потребностями и проблемами расходиться. Именно так часто и получается.

Бла-бла-бла. Реальную картинку даешь не ты, мега-программист, а характер самих данных и конечно статистика. Но её тоже надо уметь читать и понимать.


V>>Хинтами можно указать уровень блокировок. При частом обновлении это даёт прирост до нескольких раз, в особо клинических случаях — до порядка.

G>Особо клинические случаи получаются как раз по причинам, описанным выше.

Конкретно к хинтам ни одной причины не увидел.
Клинические они по самому сценарию. Вот тебе идёт обновление одной и той же немалой таблицы тысячи раз в секунду и десятки тысяч раз — запросы из неё. Хоть ужом извернись, но без ручного ковыряния хинтами ты нормально ничего не сделаешь. Часто таблицу разбивают на 2, а то и 3: актуальные (наиболее меняющиеся) данные, реже меняющиеся, исторические. Иногда делят домены на поддомены и т.д. и т.п.. И периодически перемещают данные м/у таблицами. И для разных операций разные уровни блокировки.

G>EF кстати генрит базы с READ_COMMITED_SNAPSHOT, так что блокировки, скорее всего, не станут проблемой.


Для батча с построчным изменением нескольких объектов? Ню-ню...
Ты хоть знаешь, что еще лет 10 назад за подобное любой вменяемый DBA тебя просто расстрелял бы? ))
При небольшом кол-ве построчных изменений, всё можно вложить в один запрос обновления, а не в батч, где каждый раз идет скан по таблице. Один скан на 3 ключа дешевле, чем три скана на один ключ. Хотя итоговая "математическая" сложность эквивалентна. Но вот подиж ты.

V>>Ну и "длинные транзакции" всё-равно на стороне базы исполняются на многие порядки быстрее (с тащтельно подобранными уровнями блокировки), чем последовательность вызовов Linq с клиента базы в рамках одной транзакции. От этого ты вообще никак не убежишь.

G>"Длинные транзакции" это что?

Это начало транзакции, более одной операции, конец транзакции.

G>Если у тебя один селект работает полчаса это длинная транзакция?


Это идиотизм даже по меркам 10-тилетней давности. А уж на нынешних мощщах за это кастрировать надо. Чтобы не портить общечеловеческий генофонд. Я тут ему про актуальные/исторические данные распинаюсь, про поддомены, а он мне селект на пол-часа.

G>А 1000 инсертов за секунду, отправленных одним батчем? И то и другое вполне может быть сделано как Linq, так и написано вручную.


Тупые 1000 инсертов за секунду позволял сервак на Pentium-III в своё время.


V>>Триггера те же и т.д.

V>>Понимаешь, все эти триггера, длинные транзакции и прочее используют какую-то кодовую базу SQL, которая УЖЕ есть на стороне базы. Смысл её дублировать в Linq?
G>А кто говорит что надо дублировать? Типичное распределение чтения\записи в веб-приложении — 98\2. Об оптимизации записи речи в этом плане не идет.

V>>В этом смысле Linq можно рассматривать примерно как и весь дотнет — как неплохой тул для макетирования. А "взрослая" разработка все-равно перепишет львиную долю макета в "боевой" вид.

G>Ну вот сайт сочи 2014 собрали макет и он удачно проработал...

Новостной сайт базу не нагружает от слова вообще. Эти сайты по большей части пишутся на конструкторах сайтов, где самый популярный конструктор написан на... ууупссс!... VB.Net, и весь мир прекрасно на этом работает.

Писать сегодня новостной сайт на коленке + Linq — это разновидность попила.

V>>Ты не показал, как этим пользоваться из Linq.

G>Хинты в частности и любая оптимизация вообще должна выполняться как раз знающим человеком, поэтому допускать писать хинты в Linq категорически нельзя, ибо программисты хинтами зафиксируют план, потому что им покажется что "так лучше" и оптимизировать станет возможно только путем изменения кода. Поэтому хинты только через план-гайды.

Я уже отвечал на это. Мимо.

V>>Есть мильон служебных хелперов, и? Эти хелперы связаны с состоянием базы. Ты чуть подмандил свой запрос, и твой вызванный ранее plan guide стал бесполезен. Или ты каждый раз перед целевым запросом будешь настраивать plan guide?

G>План-гайд или хинты для каждого запроса — индикатор неграмотного DBA. В базе много средств построения оптимальных планов без хинтов. Увы не все это знают. linq в этом плане помогает, ибо не дает писать хинты.

Ясно. Этот вопрос ты решил тщательно замылить.
Ты мне конкретный сценарий дай. Вот у меня идёт постоянная и одновременно частое обновление на таблице — регистре остатков. Частоту я тебе уже приводил. Без хинтов блокировок там ловить нечего. Просто поверь. Не работает.

V>>Скорее, это результат ТВОЕГО обучения. )) А есть среди них те, кто хотя бы лет 15 именно этим занимается?

G>нет, это состояние ДО обучения. Был один раз DBA с огромным опытом, чуть ли не 20 лет, имел должность "главного архитектора". С удивлением узнал про read_commited_snapshot и не очень понимал как работает статистика.

Ну тогда мне всё ясно. Прими мои соболезнования.
Я одно не понимаю! Какое нафиг отношение к нашему обсуждению имеют ГЛОБАЛЬНЫЕ настройки базы (типа твоего read_commited_snapshot), когда речь о тюнинге конкретных запросов? Этих глобальных настроек многие десятки и что с того?

Я не увидел удобного сценария, как тюнить хинтами запросы в Linq, кароч.


V>>Про impendance mismatch я вообще молчу. С грамотным DBA я наблюдал ровно противоположное — у всех всё выспросит, заставить оформить требования, ни байта лишнего из базы не отдаст.

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

Дык, у него ЗП не меньше, чем у программиста. Каждый пусть занимается своим делом.


V>>Про количество хранимок и вьюшек я написал выше. Я сразу в твоих аргументах ощутил специфический опыт, когда разработка на стороне базы фактически отсутствовала. ОК! В условиях объективной невозможности вести разработку на стороне базы, Linq тебе в помощь.

G>С чего ты взял что отсутствовала?

Ну или опыт был печален. Блин, с вами линоководами смешные разговоры выходят. Как послушаешь вас, так до Linq ни одного приложения на БД толком не взлетело и это идёт как основной аргумент. Ребят, это у ВАС не взлетело. А весь мир давно успешно пользуется базами без Linq. Например, ни в один банк ты со своим Linq не сунешься, кроме как для маргинальной неспешной аналитики под прихоть и ответственность какого-нить старшего менеджера. В рабочий процесс ЭТО не пустят на сегодня. Таковы реалии.

V>>Правда, и до Linq был тот же Hibernate/NHibernate со своим построителем запросов. ))

G>там постритель запросов с трудом осиливает джоины и предикаты. Подзапросы и проекции — жопа.

Нормально он осиливает. Если пользоваться в синтаксисе "объектного построителя" как мне тут рядом давали для демонстрации прикрепления хинтов, то точно так же всё.


G>>>Если же программисты "главнее" DBA, то программисты юзают базу как тупое хранилище объектов, а DBA только пишет batch processing для самых тормозящих сценариев.

V>>И этот подход прекрасно работает, пока в таблицах сотни тыщ / единицы мильонов строк! )))
G>Ну это ели не сделать чтонить типа select N+1. Посадить производительность можно всегда, и даже Linq в этом не помешает.

Да не в этом дело. А в том, что когда вся база легко садится в ОП сервака, то наш разговор теряет смысл сам собой. И вообще становится дичью, бо надобность реляционки в таком сценарии сильно под вопросом.


G>>>Лет 7-8 назад такое было повсеместно, потом появился Linq и больше C# программистов стало понимать что происходит в базе и как сделать оптимальной работу с СУБД.

G>>>Но тебя это, видимо не коснулось. Не беспокойся, еще не поздно изучить.

V>>Что ИМЕННО надо изучить?

G>Как работает SQL.

Давай конкретней. Особенно про момент, когда программист Linq волшебным образом начинает БОЛЬШЕ ПОНИМАТЬ, что происходит в базе.


V>>И КАК C#-программист начнет понимать происходящее в базе, особенно, если разные программисты разрабатывают разные абстрактные предикаты, из которых собирается целевой запрос "кем-то еще"? Даже по неизвестной заранее таблице? Как преодолеть ту пропасть между мышлением "типами" у программиста и "доменами" у DBA? ))

G>Изучать и SQL, и C#.

Это не ответ на выделенное. Ты хоть вопрос понял?



V>>Нет, не динамические. Подготавливается заранее view, скрывающий всю сложность низлежащего запроса, а уже на результат можно накладывать сортировку и фильтрацию. View делается DBA, конкретный тупой SQL-запрос к этому view пишет программист. Но он же тривиальный, много ума не надо, бо по специально заточенному view идёт тупой "select * from ... where ... order by ...".


G>так where и orderby каждый раз будут разными, это все равно не динамический запрос?


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


G>>>Что ты имеешь ввиду под динамическими запросами?


V>>С динамической структурой, затрагивающей подзапросы. Т.е. где в условиях идут еще выборки или групповые операции над ними, типа exists, any и т.д. из этой оперы. С перекрестными связями по-условию м/у подуровнями — прикольнее всего. ))

G>А чем такие запросы в принципе отличаются от "select * from .. where ..." где предикаты формируются в UI (с точки зрения SQL)?

Чем сложнее тело вьюшки, тем более больше отличий, вестимо.
Ты всерьез спрашиваешь или как? ))


V>>Это список полей статичный, а запрос к базе может быть очень даже динамичным в том смысле, что я написал выше.

G>Увы, не могу понять твое определение динамичности. Для SQL это такой же запрос.


G>>>Давай по порядку: что ты называешь динамическими запросами?


V>>Ну я заведомо исключил из них те, где меняются простые параметры, бо для ТАКИХ сценариев вообще Linq не облокотился и обсуждать сразу нечего.

V>>Я рассматриваю те сценарии, где Linq еще хоть зачем-то нужен, например, если ты заранее не знаешь, какой будет конечный join.
G>Что значит "заранее не знаешь" ?

Ну вот так. Добавил сравнение со статистикой — вот тебе лишняя операция реляционной алгебры (всё-равно все подзапросы, а так же exists/any/all/some и т.д. идут унутре через разновидности джоинов). Добавил сравнение в другим элементом, встречающимся в другом поддомене — вот тебе дополнительный джоин на другую таблицу.

G>>>Я грешным делом подумал что называешь динамическими запросы, которые клеятся по кускам, но прочитав твой ответ я понял, что не понял что ты называешь динамическими запросами.

V>>Это запросы с неизвестной заранее структурой и уровнями вложенности. Например, в одной из систем был способ визуального построения иерархического фильтра и простенький DSL к нему, для пользования клиентами.
G>И что? Он все равно давал на выходе конечное множество запросов.

На выходе ващет бесконечное мн-во запросов.


G>Чем такая штука принципиально отличается от грида с настраиваемыми сортировками? (опять же с точки зрения SQL).


Тем, что для грида можно написать низлежащую вьюшку лишь однажды.
Re[21]: Entity Framework за! и против!
От: vdimas Россия  
Дата: 30.06.14 14:51
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

V>>Сам запрос в Linq формируется тупым переводом структуры исходного выражения.


НС>Лучше не пиши того, о чем не знаешь. Даже если никаких оптимизаций не делать тупой перевод LINQ в SQL все равно невозможен, там разная структура запросов и разные языковые возможности. IT тут не зря написал, что собственный linq провайдер это очень сложно и дорого.

НС>Вообще, читая тут твои сообщения складывается стойкое ощущение, что в твоем представлении LINQ это просто встроенный в C# SQL.

Я очень внимательно слежу за разработками коллеги IT c 2003-го года, если что... И не раз его либы использовал во всех их 3-х основных этапах жизни. ))
Много чего дорабатывал под свои нужды (маппинг на массив объектов, описанных как value-type, например). Скажу больше, если бы разрешили, еще бы в 2006-м добавили свою визуальную дизайн-тайм приблуду над его ORM. У нас было оч удобно.

"Тупой" подразумевал без оптимизации, то бишь без "понимания" самого запроса. Это на клиентской стороне практически всегда и невозможно. Почему — отдельная тема. Правда, неинтересная, бо прошли её еще лет 10 назад, всё и так ясно.
Re[21]: Entity Framework за! и против!
От: vdimas Россия  
Дата: 30.06.14 15:08
Оценка: -1
Здравствуйте, Ночной Смотрящий, Вы писали:


НС>>>Хинты и LINQ, в общем случае, перпендикулярны.

V>>А в синтаксисе именно LINQ?

НС>Сто такое "синтаксис LINQ"? Если ты про query comprehension, то это не обязательная и даже не основная его часть. Я, к примеру, ей вообще не пользуюсь.


Э нет! Когда приводят примеры именно крутости Linq в том плане, что он позволил построить сложный запрос, в котором на SQL сам чёрт ногу сломит, то приводят именно встроенный синтаксис. И я даже иногда бываю согласен.

А в приведенном тобой виде, повторюсь, мы могли это еще в 2004-м. ))


V>>Так-то у нас "объектный" построитель запросов в похожем синтаксисе


НС>Похожесть тебе только показалась. Ключевой момент здесь — наличие expression tree, которого в 2004 не было. А QC это так, мелочевка.


Это у вас не было. А у нас — практически все используемые по-факту операции в выражениях T-SQL. И переопределение операторов, ес-но, для вменяемого синтаксиса.


НС>>>Ага, а потом я в таких проектах переписываю хранимки на linq2db и получаю ускорение в 2-3 раза.

V>>За счет чего именно?

НС>За счет того что выкидывается куча странного кода внутри хранимок. Особо весело выходит, когда одна хранимка вызывает другую, та третью и т.д.


Так это специально так делается. Хранимки и надо декомпозировать, если есть некие условия "верхнего" уровня.
Внутри одной хранимки может быть криво закеширован план, увы. MS SQK этим страдал. Не знаю как сейчас.

V>>Я бы мог ответить "это твой опыт, такой у вас был ДВА и т.д."

НС>Проблема только в том, что я в куче проектов такое видел. А, судя по общению с коллегами, не только я.

V>>Тем более, что самые "тяжелые" хранимки (по моему субъективному опыту) ни на какой Linq не перенесешь, бо там несколько операций с промежуточными таблицами, обычно


НС>Во-во, навертят бреда вокруг промежуточных таблиц на ровном месте с десятком select into, а потом оказывается что все можно переписать без них.


До снятия ограничений с табличных ф-ий на рекурсию и до введения рекурсивных возможностей в SQL — нифига не всё.
Да и сейчас тоже.
Опять же. В любом случае, в процессе таких же точно вычислений точно так же создаются промежуточные результаты во временных таблицах, просто неявно. Вряд ли ты покажешь существенный прирост скорости, бо происходит одно и то же. А код с промежуточными результатами зачастую намного проще и, опять же, замечательно поддаётся декомпозиции и повторному использованию.


V>>>>Зачем же снова и снова строить одни и те же запросы в рантайм? )))

НС>>>Нормальные linq провайдеры умеют запросы кешировать.
V>>Речь об общей кодовой базе. Повторного использования кода на стороне БД, при разработке именно со стороны БД оч много.

НС>Моя практика в рамках нескольких разнородных проектов показывает наоборот, такого кода очень мало. 90% запросов уникальны.


Ну а по моей практике, уникальны 90% простых вьюшек и табличных ф-ий, составляющих "низкоуровневый" слой. А что-то более-менее сложное делается уже на основе имеющихся простых вьюшек и тех же табличных ф-ий. А какой смысл многократно расписывать одни и те же комбинации джоинов?
Re[9]: Entity Framework за! и против!
От: IB Австрия http://rsdn.ru
Дата: 30.06.14 15:11
Оценка:
Здравствуйте, gandjustas, Вы писали:


G>Покажи пример где EF последней версии генерит неэффективный запрос.



     Order[] orders = context.Set<Order>().Include( o => o.Products).ToArray();

Генерится SQL, который в два раза менее эффективен, чем генерил в свое время linq2SQL. И это один из наиболее частых сценариев, то есть это приговор инструменту...

А знаешь почему запрос такой тормозной и они так и не поправили его за пять лет? Потому что для корректной работы маппинга EF через внутреннюю модель, нужно сгенерить дополнительный столбец, по которому не построишь индекс, а потом еще и отсортировать по этому столбцу.
То есть нельзя просто взять и поправить генерацию запросов для сценария потомок-родитель — нужно переделывать всю архитектуру генерации запросов. А эта архитектура, в свою очередь, явилась следствием дурацкой идеологии.
Как видишь, иногда полезно все-таки понимать изначальную идею решения и оценивать ее адекватность, а не бросаться сразу осваивать все что предложили.
Мы уже победили, просто это еще не так заметно...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.