Re[7]: В сотый раз про сущности EF и бизнес-объекты...
От: IT Россия linq2db.com
Дата: 22.09.17 04:57
Оценка:
Здравствуйте, Shmj, Вы писали:

IT>>Мне даже интересно, что же такого в EF неправильного, что в нём не следует писать сложные запросы? Можешь как-то сформулировать проблему?

S>При использовании так нелюбимого многими паттерна Repository и UnitOfWork можно без боли медленный метод перенести в хранимую процедуру.

При чём тут это? Я спрашиваю, какие проблемы в EF ведут к тому, что оно не может обрабатывать сложные запросы? Мне правда интересно.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: В сотый раз про сущности EF и бизнес-объекты...
От: Doc Россия http://andrey.moveax.ru
Дата: 22.09.17 05:37
Оценка:
Здравствуйте, Danchik, Вы писали:

D>И это вы автору linq2db написали


Да хоть разработчику самого .NET. Дальше что?
Рекомендую поглядеть на название топика и глянуть обсуждения. Мы про linq2db или про EF тут?
Re[6]: В сотый раз про сущности EF и бизнес-объекты...
От: Doc Россия http://andrey.moveax.ru
Дата: 22.09.17 05:45
Оценка:
Здравствуйте, IT, Вы писали:

IT>Мне даже интересно, что же такого в EF неправильного, что в нём не следует писать сложные запросы? Можешь как-то сформулировать проблему?


В таких ситуациях EF 6 склонен выдавать не оптимальные SQL запросы. На практике, то же самое — сделанное на SQL работает в разы быстрее.
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: Shmj Ниоткуда  
Дата: 22.09.17 07:45
Оценка:
Здравствуйте, IT, Вы писали:

IT>При чём тут это? Я спрашиваю, какие проблемы в EF ведут к тому, что оно не может обрабатывать сложные запросы? Мне правда интересно.


Ограниченность вестимо. Есть ли в EF поддержка курсоров SQL? Насколько я знаю -- нет.
Re[7]: В сотый раз про сущности EF и бизнес-объекты...
От: Max Mustermann  
Дата: 22.09.17 08:39
Оценка: +1
Здравствуйте, Doc, Вы писали:

IT>>Мне даже интересно, что же такого в EF неправильного, что в нём не следует писать сложные запросы? Можешь как-то сформулировать проблему?

Doc>В таких ситуациях EF 6 склонен выдавать не оптимальные SQL запросы. На практике, то же самое — сделанное на SQL работает в разы быстрее.

Без конкретных примеров это просто сотрясание воздуха.
Это даже не считая того, что есть масса "доказаных" случаев, когда EF за счёт разбора expression tree выдаёт sql гораздо лучше "рукописного".
Re[7]: В сотый раз про сущности EF и бизнес-объекты...
От: IT Россия linq2db.com
Дата: 22.09.17 13:30
Оценка:
Здравствуйте, Doc, Вы писали:

IT>>Мне даже интересно, что же такого в EF неправильного, что в нём не следует писать сложные запросы? Можешь как-то сформулировать проблему?

Doc>В таких ситуациях EF 6 склонен выдавать не оптимальные SQL запросы. На практике, то же самое — сделанное на SQL работает в разы быстрее.

Ты хочешь сказать, что EF умничает и генерирует не то, что написал программист?
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: В сотый раз про сущности EF и бизнес-объекты...
От: IT Россия linq2db.com
Дата: 22.09.17 14:17
Оценка: +1
Здравствуйте, Shmj, Вы писали:

IT>>При чём тут это? Я спрашиваю, какие проблемы в EF ведут к тому, что оно не может обрабатывать сложные запросы? Мне правда интересно.

S>Ограниченность вестимо. Есть ли в EF поддержка курсоров SQL? Насколько я знаю -- нет.

Курсоры и производительность по идее никак не связаны между собой. Разве что на курсорах обычно в перспективе получаются более тормозные рещения
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: В сотый раз про сущности EF и бизнес-объекты...
От: Shmj Ниоткуда  
Дата: 22.09.17 17:07
Оценка:
Здравствуйте, IT, Вы писали:

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


У меня самая первая работа была, так там прога для бухгалтерии, в которой было около 1000 таблиц. Да, епта, 1000 таблиц. И помоему 15 тыс. хранимых процедур (90% из которых автогенеренные, конечно).

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

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

Если вместо курсоров дергать по 1 записи из C#-кода -- будет отрабатывать не 2 часа а 2 дня.

Да, проблема в архитектуре. Но иногда архитектура не подлежит изменению.
Re[11]: В сотый раз про сущности EF и бизнес-объекты...
От: IT Россия linq2db.com
Дата: 22.09.17 17:43
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Да, вы скажите что так делать не правильно, нужно полностью переработать архитектуру.


Конечно, скажу. Ещё скажу, что приведённый пример не демонстрирует сильную стороную курсоров, а как раз наоборот, демонстрирует их неумелое использование. Курсоры в отчётах?

S>Если вместо курсоров дергать по 1 записи из C#-кода -- будет отрабатывать не 2 часа а 2 дня.


Не надо дёргать курсоры, надо от них избавляться. Чаще всего курсоры используются как заменитель понимания и умения оперировать последовательностями данных, умения использовать SQL. Курсоры просты в понимании, просто крутим цикл и готово. Поэтому, правильное переписывание этих отчётов дало бы не 2 дня вместо 2-х часов, а 20 минут в худшем случае.

S>Да, проблема в архитектуре. Но иногда архитектура не подлежит изменению.


Если что-то не подлежит изменению, то это не означает, что то, что изменению подлежит должно делаться в рамках той же самой архитектуры.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: В сотый раз про сущности EF и бизнес-объекты...
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 24.09.17 19:56
Оценка:
Здравствуйте, IT, Вы писали:

IT>Мне даже интересно, что же такого в EF неправильного, что в нём не следует писать сложные запросы? Можешь как-то сформулировать проблему?


Главное что в EF неправильно — сама идея менять объекты с трекингом где то за сценой, а потом эти изменения пучком сбрасывать. Из-за этого мозги у девелоперов начинают работать неправильно, и на выходе получается код с кучей спецэффектов и кривые выборки, так как для изменений нужны целиковые объекты, а проекции не катят. Рефакторить такое потом — жуткий ад.
Что же касается чистых запросов — тут я сам теряюсь в догадках.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: Слава  
Дата: 24.09.17 23:20
Оценка: +1
Здравствуйте, IT, Вы писали:

IT>При чём тут это? Я спрашиваю, какие проблемы в EF ведут к тому, что оно не может обрабатывать сложные запросы? Мне правда интересно.


EF позволяет грузить объекты целиком, вместо кортежей, это приводит к желанию понаписать include'ов, после чего возникает следующее,
  Проблема 1:
 private IQueryable<FuelDispenser> LoadDispensers()
        {
            return _repositoryFactory.GetRepository<FuelDispenser>().Query()
                .Include(d => d.FuelDispenserController)
                .Include(d => d.Equipment)
                .Include(d => d.FuelDispenserController.FuelDispenserSet)
                .Include(d => d.FuelTank)
                .Include(d => d.FuelTank.Fuel)
                .Include(d => d.FuelTank.Fuel.Petrochemical)
                .Include(d => d.FuelDispenserSide)
                .Include(d => d.Equipment.Workplace);
        }

  Что в свою очередь конструирует запрос
SELECT
"B"."Id" AS "Id",
"B"."Number" AS "Number",
"B"."FuelDispenserControllerId" AS "FuelDispenserControllerId",
"B"."EquipmentId" AS "EquipmentId",
"B"."FuelTankId" AS "FuelTankId",
"B"."SideId" AS "SideId",
"B"."SortOrder" AS "SortOrder",
"C"."Id" AS "Id1",
"C"."Number" AS "Number1",
"C"."DispenserSetId" AS "DispenserSetId",
"E"."Id" AS "Id2",
"E"."Number" AS "Number2",
"E"."SortOrder" AS "SortOrder1",
"G"."Id" AS "Id3",
"G"."FuelId" AS "FuelId",
"G"."Number" AS "Number3",
"G"."FuelVolumeCalculated" AS "FuelVolumeCalculated",
"G"."Temperature" AS "Temperature",
"G"."Density" AS "Density",
"G"."FuelWeightFact" AS "FuelWeightFact",
"G"."FuelWeightCalculated" AS "FuelWeightCalculated",
"G"."MaxUpperDensity" AS "MaxUpperDensity",
"G"."MinLowerDensity" AS "MinLowerDensity",
"G"."ZondId" AS "ZondId",
"G"."FuelLevelCalculated" AS "FuelLevelCalculated",
"G"."FuelLevelFact" AS "FuelLevelFact",
"G"."FuelVolumeFact" AS "FuelVolumeFact",
"G"."DeadFuelLevel" AS "DeadFuelLevel",
"G"."UpperFuelLevel" AS "UpperFuelLevel",
"G"."MaxUpperFuelLevel" AS "MaxUpperFuelLevel",
"G"."LowerFuelLevel" AS "LowerFuelLevel",
"G"."MinLowerFuelLevel" AS "MinLowerFuelLevel",
"G"."MaxUpperWaterLevel" AS "MaxUpperWaterLevel",
"G"."WaterLevel" AS "WaterLevel",
CASE WHEN ("I"."Id" IS NULL) THEN NULL ELSE CAST(_UTF8'8X0X' AS
VARCHAR(8191)) END AS "C1",
"I"."Id" AS "Id4",
"I"."Price" AS "Price",
"I"."PetrochemicalId" AS "PetrochemicalId",
CASE WHEN ("M"."Id" IS NULL) THEN NULL ELSE CAST(_UTF8'10X0X' AS
VARCHAR(8191)) END AS "C2",
"M"."Id" AS "Id5",
"M"."Value" AS "Value",
"M"."Description" AS "Description",
"M"."IsArchived" AS "IsArchived",
"M"."Color" AS "Color",
"M"."SortNumber" AS "SortNumber",
NULL AS "C3",
NULL AS "C4",
NULL AS "C5",
NULL AS "C6",
"O"."Id" AS "Id6",
"O"."Number" AS "Number4",
"O"."X" AS "X",
"O"."Y" AS "Y",
"O"."FuelDispenserSetId" AS "FuelDispenserSetId",
"Q"."Id" AS "Id7",
"Q"."EquipmentType" AS "EquipmentType",
"Q"."Name" AS "Name",
"Q"."Path" AS "Path",
"Q"."WorkplaceId" AS "WorkplaceId",
CASE WHEN ("S"."Id" IS NULL) THEN NULL WHEN ("S"."Identity" =
CAST(_UTF8'PETROL' AS VARCHAR(30))) THEN CAST(_UTF8'10X0X' AS
VARCHAR(8191)) WHEN ("S"."Identity" = CAST(_UTF8'TTYPE' AS
VARCHAR(30))) THEN CAST(_UTF8'10X1X' AS VARCHAR(8191)) WHEN
("S"."Identity" = CAST(_UTF8'TKIND' AS VARCHAR(30))) THEN
CAST(_UTF8'10X2X' AS VARCHAR(8191)) WHEN ("S"."Identity" =
CAST(_UTF8'WORKPLACE' AS VARCHAR(30))) THEN CAST(_UTF8'10X3X' AS
VARCHAR(8191)) WHEN ("S"."Identity" = CAST(_UTF8'CONTRAGENT_TYPE' AS
VARCHAR(30))) THEN CAST(_UTF8'10X4X' AS VARCHAR(8191)) WHEN
("S"."Identity" = CAST(_UTF8'PERMISSION' AS VARCHAR(30))) THEN
CAST(_UTF8'10X5X' AS VARCHAR(8191)) WHEN ("S"."Identity" =
CAST(_UTF8'CNTRGT_GROUP' AS VARCHAR(30))) THEN CAST(_UTF8'10X6X' AS
VARCHAR(8191)) WHEN ("S"."Identity" = CAST(_UTF8'DISCONT_CND' AS
VARCHAR(30))) THEN CAST(_UTF8'10X7X' AS VARCHAR(8191)) ELSE
CAST(_UTF8'10X8X' AS VARCHAR(8191)) END AS "C7",
"S"."Id" AS "Id8",
"S"."Value" AS "Value1",
"S"."Description" AS "Description1",
"S"."IsArchived" AS "IsArchived1",
"S"."Color" AS "Color1",
"S"."SortNumber" AS "SortNumber1",
"S"."IsServer" AS "IsServer",
"S"."SelfServiceTerminalId" AS "SelfServiceTerminalId",
"S"."PermissionCategory" AS "PermissionCategory",
"S"."IsSheduled" AS "IsSheduled"
FROM          "FuelDispenser" AS "B"
INNER JOIN "FuelDispenserController" AS "C" ON
"B"."FuelDispenserControllerId" = "C"."Id"
INNER JOIN "FuelDispenserSet" AS "E" ON "C"."DispenserSetId" = "E"."Id"
INNER JOIN "FuelTank" AS "G" ON "B"."FuelTankId" = "G"."Id"
LEFT OUTER JOIN "BaseMerchant" AS "I" ON ("G"."FuelId" = "I"."Id") AND
("I"."Identity" = CAST(_UTF8'FUEL' AS VARCHAR(10)))
LEFT OUTER JOIN "BaseMerchant" AS "K" ON ("G"."FuelId" = "K"."Id") AND
("K"."Identity" = CAST(_UTF8'FUEL' AS VARCHAR(10)))
LEFT OUTER JOIN "BaseCatalogItem" AS "M" ON ("K"."PetrochemicalId" =
"M"."Id") AND ("M"."Identity" = CAST(_UTF8'PETROL' AS VARCHAR(30)))
INNER JOIN "FuelDispenserSide" AS "O" ON "B"."SideId" = "O"."Id"
INNER JOIN "Equipment" AS "Q" ON "B"."EquipmentId" = "Q"."Id"
LEFT OUTER JOIN "BaseCatalogItem" AS "S" ON ("Q"."WorkplaceId" =
"S"."Id") AND (((("S"."Identity" = CAST(_UTF8'PETROL' AS VARCHAR(30)))
OR ("S"."Identity" = CAST(_UTF8'CONTRAGENT_TYPE' AS VARCHAR(30)))) OR
(("S"."Identity" = CAST(_UTF8'PERMISSION' AS VARCHAR(30))) OR
("S"."Identity" = CAST(_UTF8'WORKPLACE' AS VARCHAR(30))))) OR
((("S"."Identity" = CAST(_UTF8'CNTRGT_GROUP' AS VARCHAR(30))) OR
("S"."Identity" = CAST(_UTF8'DISCONT_CND' AS VARCHAR(30)))) OR
((("S"."Identity" = CAST(_UTF8'PRICEING_TYPE' AS VARCHAR(30))) OR
("S"."Identity" = CAST(_UTF8'TKIND' AS VARCHAR(30)))) OR
("S"."Identity" = CAST(_UTF8'TTYPE' AS VARCHAR(30))))))
При выполнении этого запроса на подключении с юникодом возникает такая ошибка:

Dynamic SQL Error
SQL error code = -204
Implementation limit exceeded
block size exceeds implementation restriction

Означающую, что у Файрберда оно в рот не помещается. Если же работать не в юникоде, то запрос вида WHERE Name='Системный пользователь' не работает в принципе.


...и вышли из тыих олтарей мыши, крыски, усеницы, мошь, вша красная,
вша жолтая, и иные всякие твари, и несли гробы повапленные со свещами
унутри, и float в трех байтах, и null-терминированные строки, и горы
кода на дельфях, и доморощенные бинарные протоколы

Проблема 2:
Затем там отказались от Firebird и перешли на MSSQL Express, но: энергичные объектно-ориентированные программисты энергично пишут дохера кода, который через WCF выгребает кучу данных в объектном виде (EF->domain->DTO->WCF->linq->Telerik) и объединяет их на клиенте, да и на сервере при выборке оно тоже тормозит, и еще бы ему не тормозить, при 15 тысячах запросов, которые делаются из одного. В результате, мой код с рукопашным отчётом на FlowDocument и linq2db работал секунды две, а Объектно-Ориентированная Слойка с отчётами телерика скрипела примерно минут сорок.

PS: Слава богу, что я там больше не работаю.
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: Doc Россия http://andrey.moveax.ru
Дата: 25.09.17 03:45
Оценка:
Здравствуйте, IT, Вы писали:

IT>Ты хочешь сказать, что EF умничает и генерирует не то, что написал программист?


Где я такое сказал? А из твоих слов можно подумать что есть только один способ получения заданного результата

Ок, сформулирую еще раз: EF генерирует то, что в итоге выдает требуемый результат. Но т.к. результат можно достичь разными способами, то EF иногда выдает не самый оптимальный из них.
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: Doc Россия http://andrey.moveax.ru
Дата: 25.09.17 03:49
Оценка:
Здравствуйте, Max Mustermann, Вы писали:

MM>Это даже не считая того, что есть масса "доказаных" случаев, когда EF за счёт разбора expression tree выдаёт sql гораздо лучше "рукописного".


И как это отменяет того, что EF может генерировать не оптимальный код в некоторых случаях.
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: Doc Россия http://andrey.moveax.ru
Дата: 25.09.17 04:21
Оценка:
Здравствуйте, Max Mustermann, Вы писали:

MM>Без конкретных примеров это просто сотрясание воздуха.


Ну например, надо удалить записи попадающие под некое условие (и таких записей может быть очень много).
Re[9]: В сотый раз про сущности EF и бизнес-объекты...
От: IT Россия linq2db.com
Дата: 25.09.17 04:27
Оценка:
Здравствуйте, Слава, Вы писали:

С>Затем там отказались от Firebird и перешли на MSSQL Express, но: энергичные объектно-ориентированные программисты энергично пишут дохера кода, который через WCF выгребает кучу данных в объектном виде (EF->domain->DTO->WCF->linq->Telerik) и объединяет их на клиенте, да и на сервере при выборке оно тоже тормозит, и еще бы ему не тормозить, при 15 тысячах запросов, которые делаются из одного. В результате, мой код с рукопашным отчётом на FlowDocument и linq2db работал секунды две, а Объектно-Ориентированная Слойка с отчётами телерика скрипела примерно минут сорок.


Ну это вряд ли проблема EF. Это скорее как обычно проблема в "орхетиктуре".
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: IB Австрия http://rsdn.ru
Дата: 25.09.17 11:03
Оценка:
Здравствуйте, Max Mustermann, Вы писали:

MM>Без конкретных примеров это просто сотрясание воздуха.

Вам надо примеров — их есть у меня.
Во всех случаях запросов один-ко-многим, EF строит план, примерно в два раза хуже оптимального, так как ему нужно выгрести дополнительные метаданные, что выливается в лишний подзапрос, который приложению нафиг не нужен.
http://rsdn.org/forum/flame.comp/5670024.1
Автор: IB
Дата: 01.07.14

И я сильно удивлюсь, если запросов с left join в приложении меньше половины. Иными словами, минимум половина запросов в приложении выполняется в два раза медленнее чем могло бы, просто потому что EF.

MM>Это даже не считая того, что есть масса "доказаных" случаев, когда EF за счёт разбора expression tree выдаёт sql гораздо лучше "рукописного".

Hard to believe. Он просто архитектурно устроен так, что оптимизировать именно на уровне expression tree крайне затруднительно, слишком много уровней абстракции внутри.
Мы уже победили, просто это еще не так заметно...
Re[8]: В сотый раз про сущности EF и бизнес-объекты...
От: IB Австрия http://rsdn.ru
Дата: 25.09.17 11:05
Оценка:
Здравствуйте, IT, Вы писали:

IT>Ты хочешь сказать, что EF умничает и генерирует не то, что написал программист?

Да. Ему нужны еще дополнительные метаданные для каких-то своих внутренних нужд и для этого он лепит дополнительные подзапросы.
Мы уже победили, просто это еще не так заметно...
Re[7]: В сотый раз про сущности EF и бизнес-объекты...
От: IB Австрия http://rsdn.ru
Дата: 25.09.17 11:17
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Что же касается чистых запросов — тут я сам теряюсь в догадках.

Основная проблема с EF в том, что там нет чистых запросов. Изначально, как ты помнишь, он делался как всемогутер, работающий через промежуточный слой. А слой этот представляет из себя некую абстрактную объектную модель, которая знает как мапить объекты на таблицы и обратно, в результате, все маппинги и запросы так и ходят через эту прослойку. Даже когда стало понятно, что такой подход не работает, отключить ее толком не удалось, только скрыть от прикладных разработчиков, а так все по прежнему работает через этот дымоход. Там же до сих пор хвосты ObjectSpaces торчат.
Отсюда и все косяки с EF.
Мы уже победили, просто это еще не так заметно...
Re[9]: В сотый раз про сущности EF и бизнес-объекты...
От: IT Россия linq2db.com
Дата: 25.09.17 13:08
Оценка:
Здравствуйте, Doc, Вы писали:

IT>>Ты хочешь сказать, что EF умничает и генерирует не то, что написал программист?

Doc>Где я такое сказал? А из твоих слов можно подумать что есть только один способ получения заданного результата

Вообще-то, да. Так вот чтобы нагенерировать всякой отсебятины нужно постараться.

Doc>Ок, сформулирую еще раз: EF генерирует то, что в итоге выдает требуемый результат. Но т.к. результат можно достичь разными способами, то EF иногда выдает не самый оптимальный из них.


Можно пример когда EF генерирует что-то непотребное? А то у меня большие сомнения.
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: В сотый раз про сущности EF и бизнес-объекты...
От: IB Австрия http://rsdn.ru
Дата: 25.09.17 13:37
Оценка: +1
Здравствуйте, IT, Вы писали:

IT>Можно пример когда EF генерирует что-то непотребное? А то у меня большие сомнения.

http://rsdn.org/forum/flame.comp/5670024.1
Автор: IB
Дата: 01.07.14
Мы уже победили, просто это еще не так заметно...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.