【MVC+MySQL+EntityFramework】查询性能优化笔记

通过在DbContext中定了表之间的关系,查询后在View中通过item.ProjectOverHour来显示关联表数据。

            modelBuilder.Entity<ProjectOverHour>()
                .HasMany(e => e.DailyReports)
                .WithRequired(e => e.ProjectOverHour)
                .HasForeignKey(e => new { e.ProjectIndex, e.EmployeeId, e.ReportDate })
                .WillCascadeOnDelete(false);

开发完后发现页面仅仅显示10条记录耗时已经超过1s了。

调查后发现如下原因:

1、EntityFramework中,关联表数据不是在查询时加载的,而是在用到时(即View中调用item.ProjectOverHour时)才会去DB查询。

将画面显示条数改为20条后,页面加载时间成正比例上升。

考虑不让EntityFramework执行多次查询,使用Select方法使其一次查询出所需要的关联数据。

Select<DailyReport, DailyReportSearchResultViewModel>(d => new DailyReportSearchResultViewModel()
                {
                   ...
                   OverHour = d.ProjectOverHour.OverHour,
                   ...
                });

这样修改后生成的SQL中关联了需要的表,并且只执行了一次查询。

因为在DbContext中定义的是外键关系,导致生成的SQL文是InnerJoin的关系,而不是想定的LeftJoin关系。

调查后没有发现如何在DbContext中定义Left Join关系。(有WithOptional方法,但执行时总是出错)

后来改用如下写法,实现了Left Join的效果,查询结果也是正确的。

from d in dailyReportsQuery
join ot1 in db.ProjectOverHours
   on new { ProjectIndex = d.ProjectIndex, EmployeeId = d.EmployeeId, ReportDate = d.ReportDate }
   equals new { ProjectIndex = ot1.ProjectIndex, EmployeeId = ot1.EmployeeId, ReportDate = ot1.WorkDate } into ottemp
from ot in ottemp.DefaultIfEmpty()
select new DailyReportSearchResultViewModel
{
   ...
   ApprovalOverHour = ot.ApprovalOverHour,
   ...
};

但是页面加载时间仍然很长(4s左右)。

后来发现把关联表中的两个View的算法改为Template后,数据查询快了很多。

这个感觉很没道理,查询应该Meger查询更快才对。

在用生成的SQL测试时,发现创建索引占据了99%的时间。

原来关联View的业务主键,在原来的表里并不是主键。

将原来的表里追加相应的索引后,查询快了很多。

逐个把关联的表都加了索引。

上述修改后,数据少时页面加载页很快(0.1s左右)。

但是在追加了2w条数据后再测试时,发现页面加载又变慢了。

还是EntityFramework生成的SQL文的问题。

因为使用OrderBy来排序,并且使用了分页,生成的SQL文变成了如下的形式。

SELECT
    ...
FROM (SELECT
    ...
FROM `dailyreport` AS `Extent1`
LEFT OUTER JOIN ...
INNER JOIN ...
 WHERE (0 = `Extent1`.`DeleteFlag`) ... ) AS `Project1`
 ORDER BY
`Project1`.`...` DESC,
`Project1`.`...` ASC,
`Project1`.`...` DESC
LIMIT 0,10

把查询结果作为子查询,然后再排序和分页。

查询用时1.1s,其中Sending data占了99%的时间。

仍然比最初的页面加载时间要多。

最后改为将InnerJoin的表用Select方法取出相关数据,LeftJoin的表的数据,通过循环Select结果集,单独取得这些数据。

修改后开发环境页面加载时间在0.2~0.3s,服务器环境在0.4~0.5s。

虽然不是很理想,但是对于社内用的小系统来说,性能已经可以接受了。

2、MySql的DB服务器是放在一台虚拟机上的,性能一直不好,并且已经有别的系统在用。

因为要用到该DB服务器上的另一个数据库的数据,所以考虑把本系统的数据建立在一台新机器上,然后建立远程连接表来取数据。

但发现每次查询都要从远程服务器取得所有的数据然后再查询,效率极差。

最后还是只好放在该服务器上了。

CREATE TABLE IF NOT EXISTS `tablename`` (
    ......
) ENGINE=FEDERATED DEFAULT CHARSET=utf8
CONNECTION=‘mysql://user:[email protected]:3306/schema/tablename‘;

如果DB能换台性能好些的服务器,应该能带来不少的提升。

时间: 2024-10-06 06:28:22

【MVC+MySQL+EntityFramework】查询性能优化笔记的相关文章

MySQL之查询性能优化四

MySQL的万能"嵌套循环"并不是对每种查询都是最优的.不过还好,mysql查询优化器只对少部分查询不适用,而且我们往往可以通过改写查询让mysql高效的完成工作.在这我们先来看看mysql优化器有哪些局限性: 1.关联子查询 mysql的子查询实现得非常糟糕.最糟糕得一类查询是where条件中包含in()的子查询语句. 例如,我们希望找到sakila数据库中,演员Penlope Guiness参演的所有影片信息. 很自然的,我们会按照下面的方式用子查询实现: select * fro

MySQL之查询性能优化

为什么查询速度会慢 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中"执行"可以认为是整个生命周期中最重要的阶段,这其中包括了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序.分组等. 在完成这些任务的时候,查询需要在不同的地方花费时间,包括网络,CPU计算,生成统计信息和执行计划.锁等待(互斥等待)等操作,尤其是向底层存储引擎检索数据的调用操作,这些调用需要在内存操作.CPU操作和内存

MySQL之查询性能优化一

只有当查询优化,索引优化,库表结构优化齐头并进时,才能实现mysql高性能. 在尝试编写快速的查询之前,需要清楚一点,真正重要是响应时间. 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后再服务器上进行解析,生成执行计划,执行,并返回结果给客户端. 其中"执行"可以认为是整个生命周期最重要的阶段,这其中包括了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序,分组等. 对于一个查询的全部生命周期,上面列的并不完整.这里我们只是想说:了解查询的生命周期,

MySQL之查询性能优化五(优化特定类型的查询)

本文将介绍如何优化特定类型的查询. 1.优化count()查询 count()聚合函数,以及如何优化使用了该函数的查询,很可能是mysql中最容易被误解的前10个话题之一 count() 是一个特殊的函数,有两种非常不同的作用.它可以统计某个列值的数量,也可以统计行数. 统计列值 要求列值是非空的.(不统计null,即null值计数为0) count()的另一个用处是统计结果集的行数.当mysql确认括号的表达式值不可能为空时,实际上就是统计 行数.最简单的就是当我们使用count(*)的时候,

MySQL分页查询性能优化

当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点.下面简单说一下我知道的一些方法. 准备工作 为了对下面列举的一些优化进行测试,下面针对已有的一张表进行说明. 表名:order_history 描述:某个业务的订单历史表 主要字段:unsigned int id,tinyint(4) int type 字段情况:该表一共37个字段,不包含text等大型数组,最大为varcha

mysql笔记03 查询性能优化

查询性能优化 1. 为什么查询速度会慢? 1). 如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数,要么让子任务运行的更快. 2). 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器端,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中"执行"可以认为是整个生命周期中最重要的阶段,这其中包括 大量为了检索数据到存储引擎的调用以及调用后

170727、MySQL查询性能优化

MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下我们从数据库的索引和查询语句的设计两个角度介绍如何提高MySQL查询性能. 数据库索引 索引是存储引擎中用于快速找到记录的一种数据结构.索引有多种分类方式,按照存储方式可以分为:聚簇索引和非聚簇索引:按照数据的唯一性可以分为:唯一索引和非唯一索引:按照列个数可以分为:单列索引和多列索引等.索引也有多

高性能mysql 第六章查询性能优化 总结(上)查询的执行过程

6  查询性能优化 6.1为什么查询会变慢 这里说明了的查询执行周期,从客户端到服务器端,服务器端解析,优化器生成执行计划,执行(可以细分,大体过程可以通过show profile查看),从服务器端返回客户端结果. 而执行部分作为最重要的一环,需要做的事情比较多,而不合适的query往往让执行过程做了不必要的操作,或者不能使用更优秀的底层数据结构,从而用时更久. 6.2慢查询基础:优化数据访问 访问数据量多大,超过实际所需是慢查询的一个原因.导致这种情况的原因大致有两个 1.应用程序向mysql

千万级记录的Discuz论坛导致MySQL CPU 100%的优化笔记

千万级记录的Discuz论坛导致MySQL CPU 100%的优化笔记 2007年3月,我写过一篇文章<解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记>( http://www.xiaohui.com/weekly/20070307.htm ),谈到自己在解决一个拥有 60 万条记录的 MySQL 数据库访问时,导致 MySQL CPU 占用 100% 的经过.在解决问题完成优化(optimize)之后,我发现 Discuz 论坛也存在这个问题,当时稍微提了一下: 发现此主