2010-12-30 2 views
0

Модуль, который я разрабатываю, делает множество небольших выборок, вставок и обновлений. Модификации, сделанные командами в пространстве имен SubSonic.Query (ActiveRecord is not my weapon of choice), выглядят намного быстрее, чем запросы выбора объекта по имени, написанные в LINQ.Запрос SubSonic LINQ в 3 раза медленнее, чем SubSonic.Query.Select

Он принимает 7.15s выполнить следующие LINQ запроса 1000 раз

long a = (
    from u in UserCollection 
    where u.UserId == value 
    select u.UserId 
).FirstOrDefault<long>();

Пока только 2.38s за тысячу пробегов Select запроса

long a = new SubSonic.Query.Select(provider, "UserId").From<User>() 
    .Where<User>(x => x.UserId == value).ExecuteScalar<long>();

Я взял время, чтобы посмотреть под капотом LINQ в SubSonic. Профилировщик говорит, что большая часть времени процессора DbQueryProvider.Execute звонков проводится в DbQueryProvider.GetExecutionPlan методе - 64%. 22% приходится на System.Linq.Expressions.Complie, когда DbQueryProvider.Execute использует только 6% времени.

Я полностью доволен тем, как запросы SubSonic LINQ анализируются и скомпилируются. Однако было бы замечательно иметь средство компиляции для повторения запросов SubSonic LINQ, как System.Data.Linq.CompiledQuery в Linq2Sql.

+0

Действительно ли это проблема? Это не кажется слишком медленным для реальной цели. – ykatchou

+0

Вы имеете в виду веб-приложение в реальных целях? Это проблема для меня. Представьте себе, сколько времени потребуется для совершения 400k транзакций небольших выборок и вставок. Я должен выбрать первичный ключ, так как SubSonic3 не позволяет вставить + select. – Mike

ответ

0

Мы сделали некоторые профилирования на этом тоже и обнаружили запись SubSonic. SingleOrDefault (x => x.id = someval) будет до 20 раз медленнее, чем тот же запрос, выполненный через CodingHorror. Записал его здесь: https://github.com/subsonic/SubSonic-3.0/issues/258.

Профилировщик указал на это в ExecutionBuilder.cs:

// this sucks, but since we don't track true SQL types through the query, and ADO throws exception if you 
// call the wrong accessor, the best we can do is call GetValue and Convert.ChangeType 
Expression value = Expression.Convert(
    Expression.Call(typeof (Convert), "ChangeType", null, 
        Expression.Call(reader, "GetValue", null, Expression.Constant(iOrdinal)), 
        Expression.Constant(TypeHelper.GetNonNullableType(column.Type), typeof(Type)) 
     ), 
    column.Type 
    ); 

Неудовлетворительно, потому что мне очень нравится дозвуковых/Linq.

В конце концов мы сдались, и я написал это - http://www.toptensoftware.com/petapoco. После портирования наш нагрузочный тест показал, что количество запросов в секунду увеличилось, а загрузка процессора снизилась с 80% до 5%.