Проблемы с производительностью/поддержкой кода, связанные с SELECT * на MS SQL, все еще актуальными сегодня, с современными ORM?

summary: я видел много советов против, используя SELECT * в MS SQL, из-за проблем с производительностью и ремонтопригодностью. однако многие из этих сообщений очень старые - от 5 до 10 лет! он кажется, из многих из этих сообщений, что проблемы с производительностью, возможно, на самом деле были довольно маленькими даже в свое время и в отношении проблем ремонтопригодности ( "нет, что, если кто-то изменит столбцы, и вы получали данные, индексируя массив! ваш SELECT * доставит вам неприятности!" ), современные методы кодирования и ORM (такие как Dapper) кажутся - по крайней мере, по моему опыту - для устранения таких проблемы.

и так: существуют ли проблемы с SELECT *, которые по-прежнему актуальны сегодня?


больший контекст: я начал работать в месте с большим количеством старого кода MS (сценарии ASP и т.п.), и я помогал в его модернизации, однако: большая часть моего SQL-опыта на самом деле из баз данных MySQL и PHP и ORM - это мой первый опыт работы с MS SQL - и я знаю, что между ними существуют тонкие различия. ТАКЖЕ: мои сотрудники немного старше меня, и у меня есть некоторые проблемы, которые - для меня - кажутся "старше". ( "поля с нулевыми значениями медленны! избегайте их!" ), но опять же: в этом конкретном поле у ​​них определенно больше опыта, чем у меня.

по этой причине, я также хотел бы спросить: есть ли SELECT * с современными ORM или не безопасно и разумно делать сегодня, есть ли в настоящее время онлайн-ресурсы, которые указывают на это?

спасибо!:)

Ответ 1

Этот вопрос уже давно, и никто, кажется, не в состоянии найти то, что Бен ищет...

Я думаю, что это так, потому что ответ "это зависит".

Здесь просто НЕ ЕСТЬ ОДИН.

Примеры

  • Как я уже указывал ранее, если база данных не принадлежит вам, и она может быть изменена часто, вы не можете гарантировать производительность, потому что при выборе * количество данных в строке может взорваться
  • Если вы пишете приложение, используя базу данных ITS OWN, никто не изменяет вашу БД (надеюсь), и вам нужны ваши столбцы, так что неправильно с выбором *
  • Если вы создадите какую-то ленивую загрузку с "основными свойствами", загружаемыми мгновенно, а другие загружаются позже (одного и того же объекта), вы не можете выбрать select *, потому что получаете все
  • Если вы используете select *, другие разработчики будут каждый раз думать о "думал ли он о выборе", поскольку они будут пытаться оптимизировать. Поэтому вы должны добавить достаточно комментариев...
  • Если вы создаете 3-уровневое приложение для создания больших кэшей в среднем уровне, а производительность - это тема, выполняемая кешем, вы можете использовать select *
  • Расширение 3Tier: если у вас много многопользовательских пользователей и/или действительно большие данные, вы должны учитывать каждый байт, потому что вам нужно масштабировать свой средний уровень с каждым байтом, потраченным впустую (как кто-то указал в комментариях раньше)
  • Если вы создадите небольшое приложение для 3 пользователей и несколько тысяч записей, бюджет может не дать времени для оптимизации скорости /db -layout/something
  • Поговорите с вашим dba... ОН посоветует вам WHICH утверждение должно быть изменено/оптимизировано/лишено вниз /...

Я мог бы продолжить. Там просто нет ответа ONE. Это зависит только от многих факторов.

Ответ 2

Я не буду касаться ремонтопригодности в этом ответе, только для производительности.

Производительность в этом контексте имеет мало общего с ORM.

Для сервера не имеет значения, как сгенерирован запрос, который он запускал, независимо от того, был ли он написан вручную или сгенерирован ORM.

По-прежнему плохой идеей является выбор столбцов, которые вам не нужны.

С точки зрения производительности на самом деле не имеет значения, выглядит ли запрос:

SELECT * FROM Table

или все столбцы указаны там явно, например:

SELECT Col1, Col2, Col3 FROM Table

Если вам нужно всего лишь Col1, убедитесь, что вы выбрали только Col1. Это достигается путем написания запроса вручную или путем точной настройки вашего ORM, это не имеет значения.


Почему выбор ненужных столбцов - плохая идея:

  • дополнительные байты для чтения с диска

  • дополнительные байты для передачи по сети

  • дополнительные байты для анализа на клиенте

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


Я добавлю ответы на ваши комментарии здесь.

Я понятия не имею, как обращаться к ORM, который не дает мне выбора, какие поля выбрать. Я лично постараюсь не использовать его. В общем, ORM добавляет слой абстракции, который плохо протекает. https://en.wikipedia.org/wiki/Leaky_abstraction

Это означает, что вам все еще нужно знать, как писать код SQL и как СУБД запускает этот код, но также нужно знать, как работает ORM и генерирует этот код. Если вы решите не знать, что происходит за ORM, у вас появятся необъяснимые проблемы с производительностью, когда ваша система станет более чем тривиальной.

Вы сказали, что на своей предыдущей работе вы использовали ORM для большой системы без проблем. Это сработало для вас. Хорошо. У меня есть ощущение, что ваша база данных была не очень большой (у вас были миллиарды строк?), И характер системы позволил скрыть вопросы производительности за кешем (это не всегда возможно). Система может никогда не выходить за пределы аппаратной емкости. Если ваши данные вписываются в кеш, обычно это будет достаточно быстро в любом случае. Это начинает иметь значение только тогда, когда вы пересекаете определенный порог. После чего внезапно все становится медленным, и его трудно исправить.

Обычно бизнес-менеджер проекта игнорирует возможные будущие проблемы, которые никогда не могут произойти. У бизнеса всегда есть более неотложные неотложные проблемы. Если бизнес/система растет настолько, что производительность становится проблемой, она либо накопит достаточное количество ресурсов для реорганизации всей системы, либо продолжит работу с увеличением неэффективности, или если система будет действительно критически важна для бизнеса, дать шанс другой компании обгонять его.

Отвечая на ваш вопрос "использовать ОРМ в приложениях, где производительность является большой проблемой". Конечно, вы можете использовать ORM. Но вам может быть труднее, чем не использовать его. С учетом ORM и производительности вы должны вручную проверить код SQL, который генерирует ORM, и убедиться, что он является хорошим кодом с точки зрения производительности. Таким образом, вам все еще нужно знать SQL и конкретные СУБД, которые вы используете очень хорошо, и вам нужно хорошо знать ваш ORM, чтобы убедиться, что он генерирует код, который вы хотите. Почему бы просто написать код, который вы хотите напрямую?

Вы можете подумать, что эта ситуация с ORM vs raw SQL несколько напоминает сильно оптимизирующий компилятор С++ и записывает ваш код в ассемблере вручную. Ну, это не так. Современный компилятор С++ действительно в большинстве случаев генерирует код, который лучше, чем то, что вы можете писать вручную на ассемблере. Но, компилятор отлично знает процессор и характер задачи оптимизации намного проще, чем у вас в базе данных. ORM не имеет представления об объеме ваших данных, он ничего не знает о вашем распределении данных.

Простой классический пример top-n-per-group может быть выполнен двумя способами, и лучший метод зависит от распределения данных, которое знает только разработчик. Если производительность важна, даже когда вы пишете код SQL вручную, вам нужно знать, как СУБД работает и интерпретирует этот код SQL и выкладывает свой код таким образом, что СУБД обращается к данным оптимальным образом. Сам SQL - это абстракция высокого уровня, которая может потребовать тонкой настройки, чтобы получить максимальную производительность (например, в SQL Server есть десятки подсказок запросов). СУБД имеет некоторую статистику, и ее оптимизатор пытается ее использовать, но ее часто недостаточно.

И теперь поверх этого вы добавляете еще один слой абстракции ORM.

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

Пример. Оптимальный запрос по таблице с миллионом строк возвращается в 10 миллисекунд. Неоптимальный запрос возвращается через 1 секунду. 100 раз медленнее. Будет ли уведомление конечного пользователя? Может быть, но, вероятно, не критично. Увеличьте таблицу до миллиарда строк или вместо одного пользователя будет 1000 одновременных пользователей. 1 секунда против 100 секунд. Конечный пользователь определенно заметил бы, хотя соотношение (в 100 раз медленнее) одинаково. На практике это соотношение будет увеличиваться по мере роста данных, поскольку различные тайники станут все менее и менее полезными.

Ответ 3

Из SQL-Server-Performance-Point-of-view вы НИКОГДА НЕ используйте select *, потому что это означает, что sqlserver читает полную строку с диска или бара. Даже если вам нужны все поля, я бы предложил не делать select *, потому что вы не знаете, кто добавляет какие-либо данные в таблицу, которые не нужны вашему приложению. Для получения дополнительной информации см. Ответ @sandip-patel

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

Из ORM-Point-Of-View с меняющимися именами столбцов я бы предложил НЕ использовать select *. Вы ХОТИТЕ знать, если таблица изменится. Как вы хотите предоставить гарантию запуска своего приложения и дать правильные результаты, если вы не получите ошибок, если базовые таблицы меняются?

Личное мнение: я действительно не работаю с ORM в приложениях, которые нужно хорошо выполнять...

Ответ 4

Как правило, лучше выбрать имена столбцов явно. Если таблица получит дополнительный столбец, она будет загружена вызовом select *, где дополнительный столбец не нужен.

Это может иметь несколько последствий:

  • Больше сетевого трафика

  • Больше ввода-вывода (для чтения дополнительных данных с диска)

  • Возможно, даже больше ввода-вывода (индекс покрытия не может быть использован - сканирование таблицы выполняется для получения данных)

  • Возможно, даже больше CPU (индекс покрытия не может использоваться, поэтому сортировка данных требуется)

Exception. Единственное место, где Выбрать * в порядке, находится в подзапросе после предложения предиката Exists или Not Exists, как в:

Select colA, colB
From table1 t1
Where Exists (Select * From Table2  Where column = t1.colA)

Подробнее -1

Подробнее -2

Подробнее -3

Ответ 5

Точка работоспособности.

Если вы делаете "Выбрать * из таблицы"

Затем я изменяю таблицу и добавляю столбец.

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

Это создает ночную кобылу для будущих ревизий, потому что вам нужно идентифицировать все места для выбора *.

Разница в скорости настолько минимальна, что меня это не волнует. Существует разница в скорости использования Varchar vs Char, Char быстрее. Но разница в скорости настолько минимальна, что почти не стоит говорить.

Выберите * самая большая проблема с изменениями (добавлениями) к структуре таблицы.

Кошмар. Знак младшего программиста и плохой код проекта. При этом я все еще использую select *, но намерен удалить его, прежде чем перейти к созданию своего кода.