Почему ORM считают хорошим но “выбором *” рассмотренный плохо?

35
задан Community 23 May 2017 в 12:34
поделиться

11 ответов

В моем ограниченном опыте вещи состоят в том, как Вы описываете - это - грязная ситуация и обычная отговорка, "это зависит" ответ, применяется.

А хорошим примером был бы интернет-магазин, на который я работаю. Это имеет Brand объект, и на основной странице веб-сайта, все бренды, которые продает хранилище, перечислены на левой стороне. Для отображения этого меню брендов всему сайту нужно, целое число BrandId и строка BrandName. Но эти Brand объект содержит целую полную лодку других свойств, прежде всего Description свойство, которое может содержать существенно большую сумму текста о Brand. Никакие два пути об этом, загружая всю ту дополнительную информацию о бренде только для выкладывания его имени в незаказанном списке не (1) в известной мере и значительно медленные, обычно из-за полей крупного текста и (2) довольно неэффективны когда дело доходит до использования памяти, создавая большие строки и даже не смотря на них перед выбрасыванием их.

Одна возможность, предоставленная многими ORMs, является к ленивой загрузке свойством. Таким образом, нам можно было возвратить Brand объект нам, но что трудоемкий и тратящий впустую память Description поле - только когда мы пытаемся вызвать get средство доступа. В том, точка, объект прокси прервет наш вызов и высосет вниз описание из базы данных как раз вовремя. Это иногда достаточно хорошо, но записало меня достаточно раз, что я лично не рекомендую его:

  • легко забыть, что свойство лениво загружается, представляя ИЗБРАННУЮ проблему N+1 только путем записи цикла foreach. Кто знает то, что происходит, когда LINQ принимает участие.
  • , Что, если своевременный вызов базы данных перестал работать, потому что транспорт сбивался с толку или сеть вышла? Я могу почти гарантировать, что любой код, который делает что-то столь же безвредное как string desc = brand.Description, не ожидал что простой вызов бросать DataAccessException. Теперь Вы только что отказали противным и неожиданным способом. (Да, я наблюдал, что мое приложение понижается трудно из-за просто этого. Научившийся на горьком опыте!)

Поэтому то, что я закончил тем, что делал, - то, что в сценариях, которые требуют производительности или подвержены мертвым блокировкам базы данных, я создаю отдельный интерфейс, который веб-сайт или любая другая программа могут назвать для получения доступа к определенным блокам данных, которым исследовали их планы запросов тщательно. Архитектура заканчивает тем, что походила отчасти на это (простите ASCII-творчество):

Web Site:         Controller Classes
                     |
                     |---------------------------------+
                     |                                 |
App Server:       IDocumentService               IOrderService, IInventoryService, etc
                  (Arrays, DataSets)             (Regular OO objects, like Brand)
                     |                                 |
                     |                                 |
                     |                                 |
Data Layer:       (Raw ADO.NET returning arrays, ("Full cream" ORM like NHibernate)
                   DataSets, simple classes)

я раньше думал, что это обманывало, ниспровергая объектную модель OO. Но в практическом смысле, пока Вы делаете этот ярлык для отображения данных, я думаю, что это в порядке. Обновление/вставление и что имеет Вас все еще, проходит полностью гидратировавшую, ORM-заполненную модель предметной области, и это - что-то, что происходит намного менее часто (в большинстве моих случаев), чем отображение конкретных подмножеств данных. ORMs как NHibernate позволит Вам сделать проекции, но той точкой я просто не вижу точку ORM. Это, вероятно, будет хранимой процедурой так или иначе, пишущий, что ADO.NET занимает две секунды.

Это - просто мои два цента. Я надеюсь читать некоторые из других ответов.

65
ответ дан Nicholas Piasecki 27 November 2019 в 06:32
поделиться

Люди используют ORM's для большей производительности разработки, не для оптимизации производительности во время выполнения. Это зависит от проекта, более ли важно максимизировать эффективность разработки или эффективность во время выполнения.

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

SELECT * не плохо, если Вам обычно нужны все столбцы в таблице. Мы не можем обобщить это, подстановочный знак всегда хорош или всегда плохо.

редактирование: Ре: комментарий doofledorfer... Лично, я всегда называю столбцы в запросе явно; я никогда не использую подстановочный знак в производственном коде (хотя я использую его при выполнении специальных запросов). Исходный вопрос о ORMs - на самом деле весьма распространено что выпуск a SELECT * платформ ORM однородно, для заполнения всех полей в соответствующей объектной модели.

Выполнение SELECT * запрос не может обязательно указать на необходимость во всех тех столбцах, и это не обязательно означает, что Вы небрежны о своем коде. Могло случиться так, что платформа ORM генерирует SQL-запросы, чтобы удостовериться, что все поля доступны в случае, если Вам нужны они.

21
ответ дан Bill Karwin 27 November 2019 в 06:32
поделиться

Linq к Sql или любая реализация IQueryable, использует синтаксис, который в конечном счете помещает Вас в управление выбранных данных. Определением запроса является также определение своего набора результатов.

Это аккуратно избегает эти select * проблема путем удаления обязанностей по форме данных от ORM.

, Например, для выбора всех столбцов:

from c in data.Customers
select c

Для выбора подмножества:

from c in data.Customers
select new
{
  c.FirstName,
  c.LastName,
  c.Email
}

Для выбора комбинации:

from c in data.Customers
join o in data.Orders on c.CustomerId equals o.CustomerId
select new
{
  Name = c.FirstName + " " + c.LastName,
  Email = c.Email,
  Date = o.DateSubmitted
}
6
ответ дан Bryan Watts 27 November 2019 в 06:32
поделиться

Существует два отдельных вопроса для рассмотрения.

Для начала это довольно распространено при использовании ORM для таблицы и объекта иметь очень отличающиеся "формы", это - одна причина, почему много инструментов ORM поддерживают довольно сложные отображения.

А хороший пример - когда таблица является частично денормализованной со столбцами, содержащими избыточную информацию (часто, это сделано для улучшения запроса или создания отчетов о производительности). Когда это происходит, более эффективно для ORM запросить просто столбцы, которых это требует, чем иметь все дополнительные столбцы, возвращенные и проигнорированные.

вопрос того, почему "Выбор *" является злым, является отдельным, и ответ попадает в две половины.

При выполнении "выбора *" сервер базы данных не имеет никакого обязательства возвратить столбцы в каком-то конкретном порядке, и на самом деле мог обоснованно возвратить столбцы в различном порядке каждый раз, хотя почти никакие базы данных не делают это.

проблема, когда типичный разработчик замечает, что возвращенные столбцы, кажется, находятся в последовательном порядке, предположение сделано этим, столбцы будут всегда быть в том порядке, и затем у Вас есть код, делающий неоправданные предположения, просто ожидая для сбоя. Хуже, тот отказ не может быть фатальным, но может просто включить, скажем, использование, 110-летнее из Рождения вместо Остаток на счете .

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

4
ответ дан Bevan 27 November 2019 в 06:32
поделиться

Я не уверен, почему Вы хотели бы частично гидратировавший объект. Учитывая класс Клиента со свойствами Имени, Address, Айдахо. Я хотел бы, чтобы они все создали полностью заполненный Потребительский объект.

список, зависающий прочь Клиентов под названием Заказы, может быть лениво загружен, когда получено доступ хотя большая часть ORMs. И NHibernate так или иначе позволяет Вам делать проекции в другие объекты. Таким образом, если Вы имели, говорится в просто списке клиентов, где Вы отобразили идентификатор и Имя, можно создать объект типа CustomerListDisplay и спроектировать запрос HQL в тот объектный набор и только получить столбцы, в которых Вы нуждаетесь от базы данных.

Друзья не позволяют преждевременным друзьям, оптимизируют. Полностью гидратируйте свой объект, ленивая загрузка, это - ассоциации. И затем представьте свое приложение, ища проблемы и оптимизируйте проблемные области.

4
ответ дан NotMyself 27 November 2019 в 06:32
поделиться

Даже ORMs должен избежать ВЫБОРА *, чтобы быть эффективным, при помощи ленивой загрузки и т.д.

И да, ВЫБРАТЬ *, обычно плохая идея, если Вы не используете все данные.

Так, у Вас есть различные виды объектов MyThing, один для каждой комбинации столбца? †“Corey Trager (15 ноября в 0:37)

нет, у меня есть объекты обзора только для чтения (которые только содержат важную информацию) для вещей как поиски и крупные наборы, и преобразуйте их в полностью гидратировавшие объекты по требованию. †“Заправка для соуса Бочонка (15 ноября в 1:22)

3
ответ дан Cade Roux 27 November 2019 в 06:32
поделиться

Случай, который Вы описываете, является ярким примером того, как ORM не является панацеей. Предложение баз данных гибкий, основанный на потребностях доступ к их данным, прежде всего, через SQL. Как разработчик, я могу легко и просто получить все данные (ВЫБОР *), или некоторые данные (ВЫБЕРИТЕ COL1, COL2), по мере необходимости. Мой механизм для того, чтобы сделать это будет понятен любому другому разработчику, занимающему проект.

для получения той же гибкости от ORM, намного больше работы должно быть сделано (или Вами или разработчиками ORM) только для возвращения Вас к месту под капотом, где Вы или получаете все или некоторые столбцы от базы данных по мере необходимости (см. превосходные ответы выше для получения смысла некоторых проблем). И весь этот дополнительный материал является просто большим количеством материала, который может перестать работать, делая систему ORM внутренне менее надежной, чем прямые вызовы SQL.

Нельзя сказать, что Вы не должны использовать ORM (моя стандартная правовая оговорка - то, что все проектные решения имеют расходы и доходы, и выбор одного или другой просто зависит) - выводят себя из строя, если это работает на Вас. Я скажу, что действительно не понимаю популярности ORM, учитывая объем дополнительной незабавной работы, которую это, кажется, создает для ее пользователей. Я буду придерживаться использования ВЫБОРА *, когда (ожидают его) я должен буду получить каждый столбец от таблицы.

2
ответ дан MusiGenesis 27 November 2019 в 06:32
поделиться

ВЫБЕРИТЕ *, не плохо. Вы спрашивали, кто бы ни полагал, что он был плох "почему?".

0
ответ дан Ali Afshar 27 November 2019 в 06:32
поделиться

ORMs в целом не полагаются на ВЫБОР *, но полагаются на лучшие методы для нахождения столбцов как определенные файлы карты данных (Будьте в спящем режиме, варианты В спящем режиме, и Apache iBATIS делает это). Что-то более автоматическое могло быть настроено путем запросов схемы базы данных для получения списка столбцов и их типов данных для таблицы. То, как данные заполняются, характерно для конкретного ORM, который Вы используете, и это должно быть хорошо зарегистрировано там.

Это никогда не хорошая идея выбрать данные, которые Вы не используете вообще, поскольку это может создать бесполезную зависимость от кода, которая может быть неприятной для поддержания позже. Для контакта с данными, внутренними к классу, вещи немного более сложны.

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

, Если бы я видел, что ORM сделал ВЫБОР * операторы, или явно или под его покрытиями, тогда я посмотрел бы в другом месте для выполнения моих потребностей интеграции базы данных.

1
ответ дан Lara Dougan 27 November 2019 в 06:32
поделиться

ВЫБЕРИТЕ *, верный признак, Вы не имеете контроля дизайном над объемом Вашего приложения и его модулей. Одна из главных трудностей при чистке чужой работы - когда существует материал там, который не является ни для какой цели, но никакого признака, что необходимо и используется, и что не.

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

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

0
ответ дан dkretz 27 November 2019 в 06:32
поделиться

Если Вы чувствуете потребность инкапсулировать все в объекте, но нуждаться в чем-то с маленьким подмножеством того, что содержится в таблице - определяют Ваш собственный класс. Запишите прямой sql (в или без ORM - большинство позволяет прямому sql обходить ограничения), и заполните свой объект с результатами.

Однако я просто использовал бы представление ORMs таблицы в большинстве ситуаций, если профилирование не сказало мне не.

0
ответ дан Josh Smeaton 27 November 2019 в 06:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: