Проблемы с базой данных и производительностью EF? - PullRequest
0 голосов
/ 18 декабря 2008

У меня есть в основном sql select вопрос, на который люди давали мне разные ответы на протяжении многих лет. Скажем, у меня есть пара таблиц, каждая из которых имеет более 40 столбцов и потенциально может содержать десять и тысячи строк, я использую SqlServer2005.

При присоединении к этим таблицам в предложении where, если у меня есть такие вещи, как

select * from t1, t2
where t1.UserID = 5 
and t1.SomeID = t2.SomeOtherID

некоторые люди говорят, что у вас всегда должна быть константа "t1.UserID = 5", а не после "t1.SomeID = t2.SomeOtherID", это повышает производительность выбора. В то время как другие говорят, что это не имеет значения.

Какой правильный ответ?

Кроме того, если я буду использовать ADO.NET Entity Framework для реализации моего DAL, будут ли проблемы с производительностью моделирования для таблиц с более чем 40 столбцами и выполнения операций CRUD?

Спасибо,

Ray.

Ответы [ 4 ]

4 голосов
/ 18 декабря 2008

В целом, при оптимизации базы данных вы должны сначала написать SQL, который является концептуально правильным, а затем настроить производительность, если профилирование показывает, что это необходимо. При внутреннем соединении лучше использовать SQL-92, явные ВНУТРЕННИЕ СОЕДИНЕНИЯ, чем декартовы продукты. Поэтому я бы начал с написания вашего SQL следующим образом:

SELECT * 
FROM t1
  INNER JOIN t2
    ON t1.SomeID = t2.SomeOtherID
WHERE
  t1.UserID = 5 

t1.SomeID = t2.SomeOtherID, который входит в ON-часть INNER JOIN, потому что он выражает взаимосвязь между двумя таблицами. Идентификатор пользователя, который входит в предложение WHERE, потому что это фильтр для ограничения набора результатов. Написание вашего SQL таким способом дает больше информации оптимизатору базы данных, потому что он выражает ваши намерения относительно объединения по сравнению с фильтрацией.

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

Что касается второй части вашего вопроса, то наиболее очевидное влияние на производительность заключается в том, что при выборе набора сущностей Entity Framework необходимо вернуть все свойства сущностей, которые он материализует. Итак, если у вас есть 40 столбцов, то вы будете перетаскивать эти данные обратно по проводам, если вы материализуете их как сущности. Однако можно писать запросы LINQ, которые возвращают анонимные типы, содержащие только нужные вам столбцы. Однако, чтобы сделать полный CRUD, вам нужно будет вернуть сущности.

2 голосов
/ 18 декабря 2008

Мнение людей об этом со временем будет меняться, поскольку оптимизация запросов к СУБД со временем развивалась, и разные СУБД будут использовать разные подходы. Я не могу говорить о каждой системе, но в 2008 году это вряд ли что-то изменит. YMMV, если вы заинтересованы только в конкретной системе.

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

1 голос
/ 18 декабря 2008

Я знаю, что этот ответ довольно банальный, но я бы предложил написать тесты. Запустите консольное приложение и проверьте его сами. Выполните запрос пару сотен раз и посмотрите, сколько времени потребуется для каждого пути.

Существует много суеверий, когда речь идет о производительности и оптимизации SQL-запросов. Некоторые люди делают вещи, думая, что это быстрее, но на самом деле они не проверяют свои факты. Кроме того, то, как EF или LinqToSql работают и взаимодействуют с БД, может привести к различиям в производительности, не очевидным в SQL.

Если вы оптимизируете код, вы также можете использовать профилировщик, например, RedGate ANTS. Это не бесплатно, но это может помочь найти узкие места в вашем коде. Тогда вы можете найти места в своем коде для оптимизации намного проще. Это не всегда ваша база данных замедляет ваши приложения. Или иногда вы выполняете быстрый запрос, но выполняете его миллион раз, когда вы действительно можете кэшировать результат.

0 голосов
/ 29 декабря 2008

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


SELECT Player.Name, Game.Date
 FROM Player
  INNER JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
 WHERE Game.WinnerFrags > Game.TotalFrags/2
 ORDER BY Player.Name

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


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount
 FROM Player
  LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
 WHERE Player.WeekRank >= 10
  AND Game.WinnerFrags > Game.TotalFrags/2
 GROUP BY Player.WeekRank, Player.Name
 ORDER BY Player.WeekRank

Ну, не совсем. JOIN возвращает записи для каждой игры, в которую играл игрок, или данные игрока и данные игры NULL, если игрок не играл ни в какие игры. Эти результаты будут отфильтрованы во время или после присоединения в зависимости от решения оптимизатора на основе критериев фрагмента. Это исключит все записи, которые не соответствуют критериям фрагмента. Таким образом, не будет записей группы для игроков, у которых никогда не было такой захватывающей победы. Эффективно создать ВНУТРЕННЕЕ СОЕДИНЕНИЕ .... FAIL.


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount
 FROM Player
  LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
   AND Game.WinnerFrags > Game.TotalFrags/2
 WHERE Player.WeekRank >= 10
 GROUP BY Player.WeekRank, Player.Name
 ORDER BY Player.WeekRank

Как только мы переместим критерии фрагмента в JOIN, запрос будет работать правильно, возвращая записи для всех игроков в первой десятке недели, независимо от того, достигли ли они побелки.

После всего этого краткий ответ:

Для ситуаций ВНУТРЕННЕГО СОЕДИНЕНИЯ это, вероятно, не влияет на производительность, когда вы ставите условия. Тем не менее, запросы будут более читабельными, если вы разделите условия объединения и фильтрации. И получение условия в неправильном месте может серьезно испортить результаты LEFT JOIN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...