使用多个连接和谓词优化LINQ查询

时间:2014-02-09 00:55:37

标签: c# sql performance linq entity-framework

假设我的SQL数据库中有三个表 - Users,Books和UsersBooks。

我正在寻找优化Web方法的设计/性能的方法,该方法获取用户名列表并返回包含用户及其书籍的JSON对象。我正在使用Linq2Entities和SQL Server 2008.

这个问题的动机是web方法被大量调用(并且正在增长!)所以我需要找到让它变得更精简和更精简的方法。

这是当前设计的精简版:

private string MyWebMethod(string input) {
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    List<string> userNames = serializer.Deserialize<List<string>>(input);

    using(var db = new dbContext()) {
        var usersAndBooks = from u in db.Users
                            join ub in db.UsersBooks on u.UserId equals ub.UserId
                            join b in db.Books on ub.BookId equals b.BookId
                            select new Result { User = u, UsersBooks = ub, Book = b };

        var predicate = PredicateBuilder.False<Result>();

        // Construct predicate to filter usersAndBooks down to users we care about
        foreach(var name in userNames) {
            predicate = predicate.Or(r => r.User.UserName.Equals(name));
        }

        usersAndBooks = usersAndBooks.AsExpandable().Where(predicate);

        foreach(var name in userNames) {
            // Logic to construct final {User:{Books}} JSON object   
        }
    }
}

2 个答案:

答案 0 :(得分:3)

为什么不使用.Contains

var usersAndBooks = from u in db.Users
                    where userNames.Contains(u.UserName)
                    join ub in db.UsersBooks on u.UserId equals ub.UserId
                    join b in db.Books on ub.BookId equals b.BookId
                    select new Result { User = u, UsersBooks = ub, Book = b };

我认为使用linqkit /谓词构建器/表达式访问者在这里是过度的。您基本上可以使用LINQ IN

执行SQL .Contains子句

数据库更容易优化:

WHERE User.UserName IN ('user1', 'user2', 'user3')

......比这个:

WHERE User.UserName = 'user1' OR User.UserName = 'user2' OR User.UserName = 'user3'

其次,是否真的有必要循环结果?

foreach(var name in userNames) {
    // Logic to construct final {User:{Books}} JSON object
}

...不确定这里的逻辑是什么,但你可能只能使用另一个进行转换。选择:

// Logic to construct final {User:{Books}} JSON object
var finalOutput = usersAndBooks.Select(x => new ...);

除了缓存或其他类型的快速数据传输服务(如redis)之外,我可以推荐的唯一另一件事是使用Newtonsoft JSON.Net而不是JavaScriptSerializer:

List<string> userNames = JsonConvert.DeserializeObject<List<string>>(input);

答案 1 :(得分:2)

如果需要考虑性能,请查看实施适合您网站的缓存方案。 .net框架提供了几种缓存选项,有几种第三方解决方案可供选择。

此外,除了选择缓存技术之外,您还应该决定缓存策略(整个页面,只包含页面中的某些组件等)。

诀窍是只在绝对必要时才查询数据库。

CACHING TECHNOLOGIES

其他阅读