精华内容
下载资源
问答
  • 数据库优化 - SQL优化

    万次阅读 多人点赞 2019-11-01 21:00:00
    以实际SQL入手,带你一步一步走上SQL优化之路!
    前面一篇文章从实例的角度进行数据库优化,通过配置一些参数让数据库性能达到最优。但是一些“不好”的SQL也会导致数据库查询变慢,影响业务流程。本文从SQL角度进行数据库优化,提升SQL运行效率。

    判断问题SQL

    判断SQL是否有问题时可以通过两个表象进行判断:

    • 系统级别表象
      • CPU消耗严重
      • IO等待严重
      • 页面响应时间过长
      • 应用的日志出现超时等错误

    可以使用sar命令,top命令查看当前系统状态。

    也可以通过Prometheus、Grafana等监控工具观察系统状态。(感兴趣的可以翻看我之前的文章)
    640?wx_fmt=png

    • SQL语句表象
      • 冗长
      • 执行时间过长
      • 从全表扫描获取数据
      • 执行计划中的rows、cost很大

    冗长的SQL都好理解,一段SQL太长阅读性肯定会差,而且出现问题的频率肯定会更高。更进一步判断SQL问题就得从执行计划入手,如下所示:640?wx_fmt=png

    执行计划告诉我们本次查询走了全表扫描Type=ALL,rows很大(9950400)基本可以判断这是一段"有味道"的SQL。

    获取问题SQL

    不同数据库有不同的获取方法,以下为目前主流数据库的慢查询SQL获取工具

    • MySQL

      • 慢查询日志
      • 测试工具loadrunner
      • Percona公司的ptquery等工具
    • Oracle

      • AWR报告
      • 测试工具loadrunner等
      • 相关内部视图如v$、$session_wait等
      • GRID CONTROL监控工具
    • 达梦数据库

      • AWR报告
      • 测试工具loadrunner等
      • 达梦性能监控工具(dem)
      • 相关内部视图如v$、$session_wait等

    SQL编写技巧

    SQL编写有以下几个通用的技巧:

    • 合理使用索引

    索引少了查询慢;索引多了占用空间大,执行增删改语句的时候需要动态维护索引,影响性能 选择率高(重复值少)且被where频繁引用需要建立B树索引;

    一般join列需要建立索引;复杂文档类型查询采用全文索引效率更好;索引的建立要在查询和DML性能之间取得平衡;复合索引创建时要注意基于非前导列查询的情况

    • 使用UNION ALL替代UNION

    UNION ALL的执行效率比UNION高,UNION执行时需要排重;UNION需要对数据进行排序

    • 避免select * 写法

    执行SQL时优化器需要将 * 转成具体的列;每次查询都要回表,不能走覆盖索引。

    • JOIN字段建议建立索引

    一般JOIN字段都提前加上索引

    • 避免复杂SQL语句

    提升可阅读性;避免慢查询的概率;可以转换成多个短查询,用业务端处理

    • 避免where 1=1写法

    • 避免order by rand()类似写法

    RAND()导致数据列被多次扫描

    SQL优化

    执行计划

    完成SQL优化一定要先读执行计划,执行计划会告诉你哪些地方效率低,哪里可以需要优化。我们以MYSQL为例,看看执行计划是什么。(每个数据库的执行计划都不一样,需要自行了解)explain sql640?wx_fmt=png

    字段 解释
    id 每个被独立执行的操作标识,标识对象被操作的顺序,id值越大,先被执行,如果相同,执行顺序从上到下
    select_type 查询中每个select 字句的类型
    table 被操作的对象名称,通常是表名,但有其他格式
    partitions 匹配的分区信息(对于非分区表值为NULL)
    type 连接操作的类型
    possible_keys 可能用到的索引
    key 优化器实际使用的索引(最重要的列) 从最好到最差的连接类型为consteq_regrefrangeindexALL。当出现ALL时表示当前SQL出现了“坏味道”
    key_len 被优化器选定的索引键长度,单位是字节
    ref 表示本行被操作对象的参照对象,无参照对象为NULL
    rows 查询执行所扫描的元组个数(对于innodb,此值为估计值)
    filtered 条件表上数据被过滤的元组个数百分比
    extra 执行计划的重要补充信息,当此列出现Using filesort , Using temporary 字样时就要小心了,很可能SQL语句需要优化

    接下来我们用一段实际优化案例来说明SQL优化的过程及优化技巧。

    优化案例

    • 表结构

      CREATE TABLE `a`
      (
          `id`          int(11) NOT NULLAUTO_INCREMENT,
          `seller_id`   bigint(20)                                       DEFAULT NULL,
          `seller_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
          `gmt_create`  varchar(30)                                      DEFAULT NULL,
          PRIMARY KEY (`id`)
      );
      CREATE TABLE `b`
      (
          `id`          int(11) NOT NULLAUTO_INCREMENT,
          `seller_name` varchar(100) DEFAULT NULL,
          `user_id`     varchar(50)  DEFAULT NULL,
          `user_name`   varchar(100) DEFAULT NULL,
          `sales`       bigint(20)   DEFAULT NULL,
          `gmt_create`  varchar(30)  DEFAULT NULL,
          PRIMARY KEY (`id`)
      );
      CREATE TABLE `c`
      (
          `id`         int(11) NOT NULLAUTO_INCREMENT,
          `user_id`    varchar(50)  DEFAULT NULL,
          `order_id`   varchar(100) DEFAULT NULL,
          `state`      bigint(20)   DEFAULT NULL,
          `gmt_create` varchar(30)  DEFAULT NULL,
          PRIMARY KEY (`id`)
      );
      
    • 三张表关联,查询当前用户在当前时间前后10个小时的订单情况,并根据订单创建时间升序排列,具体SQL如下

      select a.seller_id,
             a.seller_name,
             b.user_name,
             c.state
      from a,
           b,
           c
      where a.seller_name = b.seller_name
        and b.user_id = c.user_id
        and c.user_id = 17
        and a.gmt_create
          BETWEEN DATE_ADD(NOW(), INTERVAL – 600 MINUTE)
          AND DATE_ADD(NOW(), INTERVAL 600 MINUTE)
      order by a.gmt_create;
      
    • 查看数据量  

      640?wx_fmt=png

    • 原执行时间
      640?wx_fmt=png

    • 原执行计划
      640?wx_fmt=png

    • 初步优化思路

    1. SQL中 where条件字段类型要跟表结构一致,表中user_id 为varchar(50)类型,实际SQL用的int类型,存在隐式转换,也未添加索引。将b和c表user_id 字段改成int类型。
    2. 因存在b表和c表关联,将b和c表user_id创建索引
    3. 因存在a表和b表关联,将a和b表seller_name字段创建索引
    4. 利用复合索引消除临时表和排序

    初步优化SQL

    alter table b modify `user_id` int(10) DEFAULT NULL;
    alter table c modify `user_id` int(10) DEFAULT NULL;
    alter table c add index `idx_user_id`(`user_id`);
    alter table b add index `idx_user_id_sell_name`(`user_id`,`seller_name`);
    alter table a add index `idx_sellname_gmt_sellid`(`gmt_create`,`seller_name`,`seller_id`);
    

    查看优化后执行时间

    640?wx_fmt=png

    查看优化后执行计划
    640?wx_fmt=png

    查看warnings信息
    640?wx_fmt=png

    继续优化alter table a modify "gmt_create" datetime DEFAULT NULL;

    查看执行时间

    640?wx_fmt=png

    查看执行计划
    640?wx_fmt=png

    总结

    1. 查看执行计划 explain
    2. 如果有告警信息,查看告警信息 show warnings;
    3. 查看SQL涉及的表结构和索引信息
    4. 根据执行计划,思考可能的优化点
    5. 按照可能的优化点执行表结构变更、增加索引、SQL改写等操作
    6. 查看优化后的执行时间和执行计划
    7. 如果优化效果不明显,重复第四步操作
     

    系列文章

     
     

    温馨提示

    如果你喜欢本文,请关注我的个人公众号!或者关注我的个人博客www.javadaily.cn

    图片

     

     

    展开全文
  • sql优化的几种方式

    万次阅读 多人点赞 2018-11-05 10:20:46
    一、为什么要对SQL进行优化 我们开发项目上线初期,由于业务数据量相对较少,一些SQL的执行效率对程序运行效率的影响不太明显,而开发和运维人员也无法判断SQL对程序的运行效率有多大,故很少针对SQL进行专门的优化...

    一、为什么要对SQL进行优化

    我们开发项目上线初期,由于业务数据量相对较少,一些SQL的执行效率对程序运行效率的影响不太明显,而开发和运维人员也无法判断SQL对程序的运行效率有多大,故很少针对SQL进行专门的优化,而随着时间的积累,业务数据量的增多,SQL的执行效率对程序的运行效率的影响逐渐增大,此时对SQL的优化就很有必要。

    二、SQL优化的一些方法

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。    
        
    2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:    
    select id from t where num is null    
    可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:    
    select id from t where num=0    
        
    3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。    
        
    4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:    
    select id from t where num=10 or num=20    
    可以这样查询:    
    select id from t where num=10    
    union all    
    select id from t where num=20    
        
    5.in 和 not in 也要慎用,否则会导致全表扫描,如:    
    select id from t where num in(1,2,3)    
    对于连续的数值,能用 between 就不要用 in 了:    
    select id from t where num between 1 and 3    
        
    6.下面的查询也将导致全表扫描:    
    select id from t where name like '%abc%'    
        
    7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:    
    select id from t where num/2=100    
    应改为:    
    select id from t where num=100*2    
        
    8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:    
    select id from t where substring(name,1,3)='abc'--name以abc开头的id    
    应改为:    
    select id from t where name like 'abc%'    
        
    9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。    
        
    10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。    
        
    11.不要写一些没有意义的查询,如需要生成一个空表结构:    
    select col1,col2 into #t from t where 1=0    
    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:    
    create table #t(...)    
        
    12.很多时候用 exists 代替 in 是一个好的选择:    
    select num from a where num in(select num from b)    
    用下面的语句替换:    
    select num from a where exists(select 1 from b where num=a.num)    
        
    13.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。    
        
    14.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,    
    因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。    
    一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。    
        
    15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。    
    这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。    
        
    16.尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,    
    其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。    
        
    17.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。    
        
    18.避免频繁创建和删除临时表,以减少系统表资源的消耗。

    19.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。    
        
    20.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,    
    以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

    21.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。    
        
    22.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。    
        
    23.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

    24.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。
    在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

    25.尽量避免大事务操作,提高系统并发能力。

    26.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
     

     

     

    展开全文
  • 用户为本,让用户成为CSDN产品的主人,为此,我们特开设了CSDN产品公告栏,切实听取大家对新功能的反馈,定期抽取部分反馈用户...MD编辑器优化 操作更便捷 更加极客酷炫的博客皮肤 3.0上线 绑定脉脉即可获得专属勋...

    用户为本,让用户成为CSDN产品的主人,为此,我们特开设了CSDN产品公告栏,切实听取大家对新功能的反馈,定期抽取部分反馈用户赠送精美礼品一份!
    在这里插入图片描述
    在过去一周,CSDN研发团队又上线了哪些功能呢?一起看下:

    • CSDN APP发布最新版,新增大厂在线刷题功能
    • CSDN博主排名更新,原创优质博文更容易得到曝光
    • MD编辑器优化 操作更便捷
    • 更加极客酷炫的博客皮肤 3.0上线
    • 绑定脉脉即可获得专属勋章

    CSDN APP更新,新增大厂在线刷题功能

    CSDN APP产品经理换新,研发团队在高兴之余迎来更严格的挑战,研发小哥哥的发际线也与发版速度保持着正比例关系。为解决他们的单身难题,此处直接过滤照片。

    APP新版本最值得大家期待的大厂Offer刷题功能正式亮相,按照下面步骤,来测试你与大厂的距离吧:

    第一步:打开CSDN APP,没有下载的小伙伴可以去各大应用商店搜索“CSDN”下载体验
    在这里插入图片描述
    第二步:选择点击“立即加入”,选择你感兴趣的大厂题库

    在这里插入图片描述
    第三步:选择你感兴趣的职位题库,即可开始挑战
    在这里插入图片描述
    第四步:答题结束即可到Blink里面晒成绩了

    扫描下方二维码开启大厂之路

    在这里插入图片描述

    CSDN博主排名更新,原创优质博文更容易得到曝光

    创作不易,大家的每一篇原创博文/译文都值得尊重,更值得我们认真对待。新的规则着重曝光以下优质博文:

    • 鼓励大家积极发布优质的原创博文
    • 具有原创性、对他人有启发性且行文排版优雅的文章得到更多曝光
    • 与开发相关的技术分享、开发技巧、工具介绍、技术设想、业界评论、职业心得等等

    新排名系统参考的部分指标:

    博文特征

    • 博文的原创性/翻译
    • 博文的消费数据,包含文章的点赞、收藏、阅读时长、UV……
    • 博文的互动指数

    除了以上数据,以下的数据变化,也会对排名造成影响:

    • 发布违规文章,被审核不通过;
    • 博客超过一个月没有更新

    为保证准确性,博主排名暂定每周一更新,大家可以下载CSDN APP及时关注自己的排名变化。有异议的小伙伴可以添加CSDN官方小助手微信:vipcsdn ,邀您进入CSDN博客用户交流群。

    MD编辑器优化 操作更便捷

    MD编辑器对如下几点进行了具体优化:

    • icon图文对应
    • 代码片可选择语言类型应记录上次使用
    • 帮助文档优化
    • 鼠标移入说明实时显示

    在这里插入图片描述

    优化后的MD更注重博主的写作体验,快来发篇博文体验一下吧

    极客酷炫的博客皮肤 3.0上线

    UED团队根据大家博客等级的不同,分别设置了与之对应的主题:

    • 不同等级对应不同的模板;
    • 高等级版本切换到低等级后,无法再次切换到高等级模板,您只能使用同等级和以下等级的皮肤了;
    • VIP用户专属模板
      在这里插入图片描述

    绑定脉脉即可获得专属勋章

    在“账号设置”-“绑定登录账号”-“绑定脉脉”即可完成绑定,绑定完成后系统会自动赠送“脉脉勋章”、脉脉同步展示自己的最新博客。
    在这里插入图片描述
    在这里插入图片描述
    这么酷的勋章,快来体验一番吧,点击直达

    FAQ

    针对以上更新,如果您有异议或者更好的反馈,欢迎联系客服:

    • 客服QQ

    • 客服邮箱;kefu#csdn.net(把#换成@)

    展开全文
  • C++ 性能骨灰级优化(推荐)

    万次阅读 2020-11-27 08:27:31
    简单介绍 C++ 的一些常用优化

    一、前言

    • 一款游戏上线分钱,它的奖金来源如下:
      =奖金 = 流水 - 分成 - 不可描述的内容 - 人力成本 - 资源成本 - 服务器成本
    • 前面几项我们做技术的都无法改变,但是服务器成本这块,我们是有责任和义务去减少的;
    • 所谓能省则省嘛,你的代码写的越高效,服务器执行效率越高,用到的服务器 CPU 核数越少、内存越少,就越省钱,那么今天就来讲讲怎么省钱吧~~
      (本文涉及的所有内容都不含有复杂算法,全部是简单易懂的内容,适合 C++ 零基础)
      在这里插入图片描述

    二、时间复杂度

    1、定义

    • 在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。时间复杂度常用大 OO 符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。

    2、举例

    • 1)简单赋值语句(或表达式)的时间复杂度为:O(1)O(1),如下:
    	s = a[0];
    
    • 2)遍历一维数组的时间复杂度为:O(n)O(n),如下:
    	for(i = 0; i < n; ++i) {
    		s += a[i];
    	}
    
    • 3)遍历二维数组的时间复杂度为:O(n2)O(n^2),高维数组以此类推,如下:
    	for(i = 0; i < n; ++i) {
    		for(j = 0; j < n; ++j) {
    			s += a[i][j];
    		}
    	}
    
    • 4)二分查找的时间复杂度为:O(logn)O(log_n)(下文说到的所有对数,都是以 22 为底)如下:
    	l = 1, r = n;
    	while(l <= r) {
    		mid = (l + r) >> 1;
    		if(a[mid] <= v) {
    			r = mid + 1;
    		}else {
    			l = mid + 1;
    		}
    	}
    
    • 5)斐波那契数列递归枚举的时间复杂度:O(2n)O(2^n),如下:
    	int fib(unsigned int n) {
    		if(n <= 1) {
    			return n;
    		}
    		return fib(n-1) + fib(n-2);
    	}
    
    • 6)深搜枚举全排列的时间复杂度:O(n!)O(n!),如下:
    int stk[MAXN], top, has[MAXN];
    
    void dfs(int n, int depth) {
    	int i;
    	if (depth == n) {
    		for (i = 0; i < n; ++i) {
    			printf("%d", stk[i]);
    		}
    		puts("");
    	}
    	for (i = 0; i < n; ++i) {
    		if (!has[i]) {
    			has[i] = 1;
    			stk[top++] = i+1;
    			dfs(n, depth + 1);
    			--top;
    			has[i] = 0;
    		}
    	}
    }
    
    • 7)各种情况嵌套以后形成的综合场景,比如 O(n2n)O(nlogn)O(n2logn)O(n2^n)、O(nlog_n)、O(n^2log_n),不再一一举例;

    三、C++ 写法优化

    1、查找时用键值对代替数组

    1)哈希数组

    【场景1】从长度为 nn 的数组中查找某个数字是否存在

    • 利用枚举的方式,遍历所有元素进行判断,时间复杂度 O(n)O(n),代码实现如下:
    const int n = 100000;
    void init() {
    	for (int i = 0; i < n; ++i) {
    		a[i] = 5 * i;
    	}
    }
    bool find(int target) {
    	for (int i = 0; i < n; ++i) {
    		if (target == a[i]) {
    			return true;
    		}
    	}
    	return false;
    }
    
    • 这个时间复杂度是会以乘法的形式累乘到调用方的时间复杂度上的,比如调用方调用 mm 次,那么整体下来的时间复杂度就是 O(mn)O(mn),调用代码如下:
    int countBy() {
    	int cnt = 0, m = 100000;
    	while(m--) {
    		if (find(6857112) ) {  // 这里举了个最坏的例子,永远找不到的情况
    			++cnt;
    		}
    	}
    	return cnt;
    }
    
    • n=100000n = 100000 时,调用 100000100000findfind 函数,最坏情况是一次都找不到,实测时间:20313ms20313 ms
    • 所以是需要想办法优化的;

    【优化1】利用哈希数组的索引来代替数组的遍历

    • 观察到数组里的数据都是整数,而且最大不会超过 500000500000,所以可以把数组的数据映射到一个最大为 500000500000 的哈希表中,查找的时候只需要利用下标索引,时间复杂度 O(1)O(1),代码如下:
    const int n = 100000;
    void init() {
    	memset(hashtbl, 0, sizeof(hashtbl));
    	for (int i = 0; i < n; ++i) {
    		hashtbl[ 5 * i ] = 1;
    	}
    }
    bool find(int target) {
    	return hashtbl[target];
    }
    
    • n=100000n = 100000 时,调用 100000100000findfind 函数,实测时间:0ms0ms
    • 但是需要注意数组下标越界的问题,一旦越界就会导致程序崩溃或者让程序进入不确定性,安全性比较低;

    2)map

    【场景2】从长度为 nn 的数组中查找某个字符串是否存在

    • 时间复杂度:O(n)O(n)
    • 实现代码类似【场景1】,不再累述;

    【优化2】利用 STL 的 map 来代替数组的遍历

    • 观察到数组里的数据不是数字,无法直接映射到数组中,所以我们借助 STLSTLmapmap,查找的时间复杂度 O(logn)O(log_n),代码如下:
    const int n = 100000;
    map<string, bool> maphash;
    
    void init() {
    	maphash.clear();
    	for (int i = 0; i < n; ++i) {
    		maphash[ str[i] ] = 1;
    	}
    }
    bool find(string target) {
    	return maphash.find(target) != maphash.end();
    }
    
    • STLSTLmapmap 底层实现是红黑树,在进行查找的时候涉及的常数会比较大,再加上 keykey 是字符串,计算哈希函数的时间也要算上,所以实际的时间复杂度是 O(Clogn)O(Clog_n)
    • n=100000n = 100000 时,调用 100000100000findfind 函数,实测时间:563ms563ms

    3)unordered_map

    【优化3】利用 STL 的 unordered_map 来代替数组的遍历

    • unordered_mapunordered\_map 的用法和 mapmap 基本一致,代码不再累述;
    • unordered_mapunordered\_map 底层实现是哈希表,同样如果 keykey 是字符串,也有常数运算在,总体来说效率优于 mapmap,时间复杂度 O(C)O(C)
    • n=100000n = 100000 时,调用 100000100000findfind 函数,实测时间:157ms157ms

    4)效率排行总结

    • 效率排行:>unordered_map>map>哈希数组 > unordered\_map > map > 数组
    • 普适性排行:>unordered_map==map>数组 > unordered\_map == map > 哈希数组
    • 安全性:unordered_map==map>>unordered\_map == map > 数组 > 哈希数组

    【思考题1】

    • 1)以下代码时间复杂度是多少?
    • 2)请想办法把它优化到 O(n+m)O(n+m)
    	int sum = 0;
        for (int i = 0; i < n; ++i) {
            for(int j = 0; j < m; j++) {
                if(A[i] == B[j]) {
                    sum += (A[i] + B[j]);
                }
            }
        }
    

    2、关注常数优化

    • 项目大了,写的人多了,尤其是各种交叉调用的逻辑,用别人接口的时候也关注下别人实现的时间复杂度,很多逻辑其实都是乘法逻辑,一层一层叠上来,数据量大了就很恐怖了。
    • 当然,提供接口的人也要多想想调用方会以什么方式来调用,如果什么都不考虑就写出 O(n)O(n) 或者 O(n2)O(n^2) 时间复杂度的代码,这种情况下如果调用方对任何其中一个接口用法不正确,实现者至少也得负一部分责任。
    • 当外层循环大量嵌套的时候,内层的一个简单的逻辑可能会被调用千百万次,这时候一些基础接口已经到了无法优化的地步,就只能考虑常数优化了;

    1)位运算

    【场景3】计算某个玩家的属性的时候,有一步运算是除上2的幂取除数和余数

    • 基础四则运算中当属除法最为耗时,将除法单独提取出来,实现如下:
    const int n = 3000000;
    const int m = 30;
    
    int doCount() {
    	int s = 0, cnt = n;
    	int pow2[MAXP] = { 1 };
    	for (int i = 1; i < m; ++i) {
    		pow2[i] = pow2[i - 1] * 2;
    	}
    	while (cnt --) {
    		for (int i = 0; i < m; ++i) {
    			s += rand() / pow2[i];
    			s += (rand() % pow2[i]);
    		}
    	}
    	return s;
    }
    
    • 这个函数的时间复杂度 O(nm)O(nm),但是内层循环的 除法 和 取余 操作占据了大量时间,实测时间:3406ms3406 ms
    • 这里有两个优化的点:
    • 1)对 2 的幂的除法可以用右移对应位数进行优化;
    • 2)对 2 的幂取余数可以用位与 2的幂减1 进行优化;

    【优化4】利用位运算进行常数优化

    const int n = 3000000;
    const int m = 30;
    
    int doCount() {
    	int s = 0, cnt = n;
    	int pow2[MAXP] = { 1 };
    	for (int i = 1; i < m; ++i) {
    		pow2[i] = pow2[i - 1] * 2;
    	}
    	while (cnt --) {
    		for (int i = 0; i < m; ++i) {
    			s += rand() >> i;
    			s += rand() & (pow2[i]-1);
    		}
    	}
    	return s;
    }
    
    • 时间复杂度还是 O(nm)O(nm),但是将除法和取余替换成位运算后,实测时间:2706ms2706 ms

    【思考题2】

    • 利用位运算将以下代码缩减到 11 行;
    int get(int x) {
    	int c = 0;
    	while (x % 2 == 0) {
    		c++;
    		x /= 2;
    	}
    	return (1 << c);
    }
    

    2)避免重复运算

    【场景4】循环内部大量调用同一个函数,参数也相同

    • 实现代码如下:
        for (i = 0; i < n; ++i) {
            for(j = 0; j < m; j++) {
                int v = Cal(MAX_COUNT);
                A[i][j] = v * i + j;
            }
        }
    
    • 这里 CalCal 函数的时间复杂度假设为 XX,那么整个运算过程的时间复杂度就是 O(nmX)O(nmX)
    • 观察发现,CalCal 函数的计算和 iijj 无关,所以可以提到循环外面来,修改后如下:

    【优化5】改变运算顺序避免重复运算

        int v = Cal(MAX_COUNT);
        for (i = 0; i < n; ++i) {
            for(j = 0; j < m; j++) {
                A[i][j] = v * i + j;
            }
        }
    
    • 修改完后的时间复杂度为:O(nm+X)O(nm + X)

    【思考题3】

    • 简化代码使之更加高效;
        for (i = 0; i < n; ++i) {
            for(j = 0; j < m; j++) {
                A[i][j] = Cal(i) + Del(j);
            }
        }
    

    3)加法代替乘法

    • 乘法运算的效率低于加法运算,原因很好解释:你可以随便拿两个三位数在纸上试一下,乘法的运算步骤会比加法的运算步骤复杂得多;
    • 假设一个十进制数字位数为 nn 位,加法的时间复杂度为 O(n)O(n),乘法则是 O(n2)O(n^2) 的;

    【优化6】如果可行尽量用加法代替乘法

    • 还是以上面的例子为例,我们发现 A[i][j]A[i][j] 满足某种规律;
      A[i][j]={ji=0A[i1][j]+v0<i<n A[i][j] = \begin{cases} j & i=0\\ A[i-1][j] + v & 0<i<n\\ \end{cases}
    • 那么我们可以通过递推的方式将乘法改成加法,实现代码如下:
        int v = Cal(MAX_COUNT);
        for (i = 0; i < n; ++i) {
            for(j = 0; j < m; j++) {
            	if(!i) {
            		A[i][j] = j;
            	}else {
                	A[i][j] = (A[i-1][j] + v);
                }
            }
        }
    

    【思考题4】

    • 不用乘法和除法求解组合数,组合数定义如下:
      Cnm=n!m!(nm)!C_n^m = \frac {n!}{m!(n-m)!}

    4)再次优化取模

    【场景5】需要对一批数据进行求和取模

    • 取模满足 模’+’ 运算,所以可以边加边取模,实现代码如下:
    int doSumMod() {
    	int s = 0;
    	for (int i = 0; i < n; ++i) {
    		s = (s + val[i]) % MOD;
    	}
    	return s;
    }
    
    • n=100000000n = 100000000 时,该代码的运行实测时间为:891ms891 ms

    【优化7】不必要时不进行取模运算

    • 取模运算当被取模数小于模时,不需要进行取模,所以上面的写法可以改成如下:
    int doSumMod() {
    	int s = 0;
    	for (int i = 0; i < n; ++i) {
    		s += val[i];
    		if (s >= MOD) s %= MOD;
    	}
    	return s;
    }
    
    • n=100000000n = 100000000 时,该代码的运行实测时间为:187ms187 ms

    【思考题5】

    • 取模时出现负数该如何处理?
    	ans = -520 % 1314;  //???
    

    5)尽量少用 #define

    【场景6】求两个数字中的大者

    • 为了把代码写在一行里,你可能会想这么写:
    	#define MAX(a,b) ((a)>(b)?(a):(b))
    
    • 因为 #define\#define 是宏替换,所以这里的 aa 或者 bb 会计算两次,想象下如下的调用:
    	MAX(for(int i = 0; i <100000; ++i) s += i, for(int i = 0; i <100000; ++i) s += i);
    
    • 你可能会说:谁会写出这样的代码???
    • 然而,项目大了,什么代码都会有,你永远无法预料调用你代码的人的水平是怎么样的;

    【优化8】宁以 const 或者 函数代替 #define

    • 老老实实写函数吧:
    int Max(int a, int b){
    	return a > b ? a : b;
    }
    
    • 如果觉得普适性不强,想要支持 charshortfloatdoublechar、short、float、double,就搞个模板:
    template <class T>
    T Max(T a, T b){
    	return a > b ? a : b;
    }
    

    【思考题6】

    • 如下宏定义求的是一个数的绝对值,它的问题在哪里?
    	#define ABS(x) x<0?-x:x
    

    6)循环终止条件

    【场景7】循环的终止条件是一个表达式的时候

    • forfor 循环的终止条件是一个表达式的时候,每次循环都会判断条件是否满足,也就是每次循环都会进行一次表达式的计算,所以应该尽量简化表达式的计算方式,举个简单的例子如下:
    int For() {
    	int s = 0;
    	for (int i = 0; i*i < n; ++i) {
    		for (int j = 0; j*j < n; ++j) {
    			for (int k = 0; k*k < n; ++k) {
    				// TODO
    			}
    		}
    	}
    	return s;
    }
    
    • 为了把注意力集中在这个条件判断上,我跑了个空的三层循环,即运算消耗都在循环终止条件的表达式上了,那么当 n=1000000n = 1000000 时,实测的时间消耗为:2125ms2125 ms

    【优化9】尽量最大限度的简化循环终止条件的逻辑运算

    • 这段代码的终止条件基本都是平方运算,由于:
      ii<n  i<ni*i < n \ 等价于 \ i < \sqrt n
    • 我们可以把表达式进行一个转换,实现代码如下:
    int For2() {
    	int s = 0;
    	int v = sqrt(n + 1e-8);
    	for (int i = 0; i < v; ++i) {
    		for (int j = 0; j < v; ++j) {
    			for (int k = 0; k < v; ++k) {
    				// TODO
    			}
    		}
    	}
    	return s;
    }
    
    • 简化循环终止条件的运算以后,当 n=1000000n = 1000000 时,实测耗时:1453ms1453 ms

    【思考题7】

    • 对以下代码的循环终止条件进行优化;
    	for(i = 0; i < vec.size(); i++) {
    		// TODO
    	}
    

    3、分而治之

    1)二分查找

    【场景8】给定一个数,在一个有序数组中查找比它大的最小的数,不存在输出 -1

    • 对于数组中进行数据查找的问题,本文一开始就已经提到了一些解决方案;不过这个问题比较特殊,给定的数组本身是一个有序数组,对于数组元素个数为 nn 的情况,可以利用二分查找在 O(logn)O(log_n) 的时间内进行求解;

    【优化10】利用二分查找优化有序数组的查找效率

    #define MAXA 10
    int bin[MAXA] = { 1, 2, 4, 6, 8, 9, 11, 88, 520, 1314 };
    int BinarySearch(int val) {
    	int l = 0, r = MAXA - 1;
    	int m, ans = -1;
    	while (l <= r) {
    		m = (l + r) >> 1;
    		if (bin[m] > val) {
    			ans = bin[m];
    			r = m - 1;
    		}
    		else {
    			l = m + 1;
    		}
    	}
    	return ans;
    }
    

    【思考题8】

    • 如果要在一个有序数组中查找比它小的最大的数,上面的代码要怎么改?

    2)二分快速幂

    【场景9】计算 abmod  ca,b<264a^b \mod c(a,b<2^{64}) ,一般用在加解密算法(例如 RSA )中

    • 在这个问题上,又是乘方运算,又是取模运算,本身就已经很耗时了,再加上 aba,b 的数据范围,如果仅仅是枚举遍历求解,以目前计算机的水平,肯定无法在规定时间内求解的;

    【优化11】利用递归二分的性质将线性时间复杂度转换成对数时间复杂度

    • 次幂运算是最满足二分递归性质的,因为它满足如下公式:
      abmod  c={1mod  cb0a(a(b1)/2)2mod  cb(ab/2)2mod  cba^b \mod c = \begin {cases} 1 \mod c & b 为 0 \\ a(a^{(b-1)/2})^2 \mod c & b为奇数\\ (a^{b/2})^2 \mod c & b为正偶数\\ \end{cases}
      所以可以利用递归把本来 O(b)O(b) 的时间复杂度的问题转化成 O(logb)O(log_b),具体实现可以参考以下文章:
      夜深人静写算法(十九)- 快速幂

    4、了解 STL 的真实效率

    1)vector 的插入

    • STLSTLvectorvector 意为动态数组,弥补了 C++ 原生不支持动态数组的缺陷;
    • 但是它的效率实在不敢恭维,所以有时候如果不是很必要的情况下,能不用尽量不用;
    • 测试一个 vectorvector 的插入效率代码如下:
    const int MAXDC = 100;
    void DataCollect() {
    	vector <int> v;
    	for (int i = 0; i < MAXDC; ++i) {
    		v.push_back(i);
    	}
    }
    
    • 对以上函数调用 100000100000 次,实测时间为:3469ms3469 ms
    • vectorvector 的内存分配策略采用的是倍增法,会预先申请一块内存,每次插入一个元素会对当前剩余内存进行一个预见检测,如果超出这个预分配内存,会对现有内存进行倍增,并且拷贝原有内存数据到新的内存上去,所以这里面会有一些申请堆空间、构造函数、内存拷贝函数的调用等等,不免会有许多常数时间调用,具体规则参见如下文章:STL vector 扩容策略

    【优化12】对 vector 进行内存预分配

    • 如果确定 vector 的数据一定至少有 nn 个,那么我们可以利用 reservereserve 函数预先分配 nn 个元素的内存出来,这样起码会减少很多内存重分配的次数,具体实现代码如下:
    const int MAXDC = 100;
    void DataCollect() {
    	vector <int> v;
    	v.reserve(MAXDC);
    	for (int i = 0; i < MAXDC; ++i) {
    		v.push_back(i);
    	}
    }
    
    • 同样,对以上函数调用 100000100000 次,实测时间为:1437ms1437 ms,效率提升了不少;

    【优化13】小数组尽量不用 vector

    • 我们发现上面涉及的数组往往比较小,如果直接用一个固定长度为 100100 的数组也能够满足需求,那就尝试用数组来实现一下,实现代码如下:
    const int MAXDC = 100;
    void DataCollect() {
    	int stk[MAXDC], top = 0;
    	for (int i = 0; i < MAXDC; ++i) {
    		stk[top++] = i;
    	}
    }
    
    • 同样,对以上函数调用 100000100000 次,惊人的发现,实测时间为:31ms31 ms
    • 所以可以看出,如果数据量比较小,并且频繁重复调用同一个数组的数据插入时,不建议用 vectorvector
    • 但是需要注意的是,如果用数组,一定要确保数组下标在安全范围内,否则有可能引起进程的崩溃;

    2)queue 的插入和取出

    • STLSTL 的队列 queuequeue 实现了 (FIFO)(FIFO) 先进先出 的数据结构;
    • 内存分配策略基本上和 vectorvector 是一致的,所以也会面临内存重分配和数据拷贝;
    • 基于效率考虑,不建议直接用 STLSTLqueuequeue,可以自己实现一个支持扩容的队列;

    【思考题9】

    • 1)以下代码有哪些问题?
    • 2)如何优化?
    	string s;
    	for(i = 0; i < n; ++i) {
    		s += "K";
    	}
    

    5、了解底层调用

    1)慎用三角函数

    • 三角函数的计算用的是 CordicCordic 算法,整体来说是一个迭代,一些位移 和 加减法,所以如果一些常用,精度要求不高的,能够用常量代替的可以尽量用常量,比如 :3.14159273.1415927 代替 acos(1.0)acos(-1.0)
    const int MAXPI = 100000000;
    double CalcCircle() {
    	double s = 0;
    	for (int i = 0; i < MAXPI; ++i) {
    		s += acos(-1.0) * i * i;
    	}
    	return s;
    }
    
    • 以上代码实测时间:1532ms1532 ms

    【优化14】精度允许的情况尽量用常量代替三角函数

    const int MAXPI = 100000000;
    double CalcCircle() {
    	double s = 0;
    	const double PI = 3.1415927;
    	for (int i = 0; i < MAXPI; ++i) {
    		s += PI * i * i;
    	}
    	return s;
    }
    
    • 以上代码实测时间:672ms672 ms

    【思考题10】

    • 浮点数计算的时候是有精度损失的,那么如何判断两个浮点数是否相等;

    2)类型转换

    【场景10】静态类型转换 和 动态类型转换 的时耗性

    • static_caststatic\_castdynamic_castdynamic\_cast 实测下来效率差距不大;
    const int MAXT = 100000000;
    void StaticCast_Test() {
    	Inher *p = new Inher();
    	for (int i = 0; i < MAXT; ++i){
    		Base *pkBase = static_cast<Base*>(p);
    	}
    }
    void Dynamic_Test() {
    	Inher *p = new Inher();
    	for (int i = 0; i < MAXT; ++i){
    		Base *pkBase = dynamic_cast<Base*>(p);
    	}
    }
    
    • 当调用 1000000010000000 时,均为 16ms16 ms 左右;

    6、记忆化

    1)记忆化搜索

    • 记忆化搜索是动态规划(并不属于搜索范畴)的一种,思路就是将已经计算过的内容记录下来,避免下次遇到的时候重复计算,比较经典的就是递归版本的斐波那契数列的计算;

    【场景11】斐波那契数列的计算

    • 来看非记忆化版本的代码:
    	long long fib(unsigned int n) {
    		if(n <= 1) {
    			return n;
    		}
    		return fib(n-1) + fib(n-2);
    	}
    
    • 虽然代码很短,但是这个函数的实现采用了递归,参考深度优先搜索,每次往下递归相当于扩展了两个二叉树的子节点,所以算法的时间复杂度是 O(2n)O(2^n) 的,如下图所示:
    n
    n-1
    n-2
    n-2
    n-3
    n-3
    n-4
    n-3
    n-4
    n-4
    n-5
    n-4
    n-5
    n-5
    n-6

    【优化15】记忆化搜索将指数级时间复杂度转变为多项式级时间复杂度

    • 来看下经过记忆化优化以后的递归版本的斐波那契数列计算:
    	void init() {
    		memset(f, -1, sizeof(f));
    	}
    	
    	long long fib(unsigned int n) {
    		if(n <= 1) {
    			return n;
    		}
    		if(f[n] != -1) {
    			return f[n];
    		}
    		return f[n] = fib(n-1) + fib(n-2);
    	}
    
    • 利用一个静态数组来记录斐波那契数列第n项的值,并且初始化为 -1 表示没有计算过,一旦计算出来就给它赋值,下次再访问的时候直接返回已经计算出来的值即可;
    • 均摊时间复杂度 O(n)O(n)
    • 当然,还有比较常用的记忆化搜索,如区间动态规划、状态压缩,如果对动态规划感兴趣,可以参考这篇文章:夜深人静写算法(二)- 动态规划

    2)预处理

    • 记忆化 和 预处理 是两个截然相反的过程,预处理指的是在你需要某些运算信息的时候,它早就已经计算好了,而不是等到需要的时候再去重新计算,还是以斐波那契数列为例:
    	f[0] = 0, f[1] = 1;
    	for(int i = 2; i < MAXN; ++i) {
    		f[i]  = f[i-1] + f[i-2];
    	}
    
    • 这个时间复杂度很明确,是 O(n)O(n) 的,并且在接下来每次询问中,都是O(1)的;
      【优化16】预处理能够处理所有可预见范围内的计算
    • 但是预处理需要确保一个事情,就是所有的询问必须保证数据范围在预处理的数据范围内,否则就起不到预处理的作用了;

    3)前缀和

    【场景12】计算斐波那契数列的第L项到第R项的和(L<=R)

    • 朴素做法就是每次将 0R0 - R 项的和都计算出来,然后累加,时间复杂度 O(R)O(R),代码实现如下:
    	f[0] = 0, f[1] = 1;
    	for(int i = 2; i <= R; ++i) {
    		f[i]  = f[i-1] + f[i-2];
    	}
    	s = 0;
    	for(int i = L; i <= R; ++i) {
    		s += f[i];
    	}
    
    • 这个时候,如果请求的数量很多,这里其实伴随着很多冗余计算,所以这里有个技巧叫做:前缀和

    【优化17】预处理数组前缀和可以做到询问时O(1)

    • 1)利用预处理记录下所有斐波那契数列的前缀和,存储在 sum 数组,时间复杂度 O(n)O(n)
    	sum[0] = 0;
    	for(int i = 1; i < MAXN; ++i) {
    		sum[i]  = sum[i-1] + f[i];
    	}
    
    • 2)询问时通过两个前缀和相减获得所求值,时间复杂度 O(1)O(1)
    	NumberType getFib(NumberType L, NumberType R) {
    		return sum[R] - sum[L-1];
    	}
    
    • 这种情况适用于询问量非常大的情况;

    【思考题11】

    • 给定一个 100×100×100100 \times 100 \times 100 的三维数组,然后是 100000100000 次询问;
    • 每次询问问的是 (xl,yl,zl)(xr,yr,zr)(x_l,y_l,z_l)-(x_r,y_r,z_r) 这个子立方数组的和,如何最高效的求解;
    • 时间复杂度是多少;

    四、优化总结回顾

    【优化1】利用哈希数组的索引来代替数组的遍历
    【优化2】利用 STLSTLmapmap 来代替数组的遍历
    【优化3】利用 STLSTLunordered_mapunordered\_map 来代替数组的遍历
    【优化4】利用位运算进行常数优化
    【优化5】改变运算顺序避免重复运算
    【优化6】如果可行尽量用加法代替乘法
    【优化7】不必要时不进行取模运算
    【优化8】宁以 constconst 或者 函数代替 #define\#define
    【优化9】尽量最大限度的简化循环终止条件的逻辑运算
    【优化10】利用二分查找优化有序数组的查找效率
    【优化11】利用递归二分的性质将线性时间复杂度转换成对数时间复杂度
    【优化12】对 vector 进行内存预分配
    【优化13】小数组尽量不用 vectorvector
    【优化14】精度允许的情况尽量用常量代替三角函数
    【优化15】记忆化搜索将指数级时间复杂度转变为多项式级时间复杂度
    【优化16】预处理能够处理所有可预见范围内的计算
    【优化17】预处理数组前缀和可以做到询问时 O(1)O(1)

    五、思考题答案

    字数太多描述不下了,答案见下期吧

    展开全文
  • 粒子群优化算法(PSO)

    万次阅读 多人点赞 2018-06-04 20:07:09
    粒子群优化算法(Partical Swarm Optimization PSO),粒子群中的每一个粒子都代表一个问题的可能解,通过粒子个体的简单行为,群体内的信息交互实现问题求解的智能性。由于PSO操作简单、收敛速度快,...
  • 多目标优化

    万次阅读 多人点赞 2018-09-14 11:40:57
    优化问题的分类 1)无约束和有约束条件; 2)确定性和随机性最优问题(变量是否确定); 3)线性优化与非线性优化(目标函数和约束条件是否线性); 4)静态规划和动态规划(解是否随时间变化)。 - 什么是...
  • el-scrollbar 优化滚动条样式

    万次阅读 2019-12-03 19:33:16
    element-ui 隐藏组件 el-scrollbar 优化滚动条样式
  • 如何优化MySQL千万级大表,我写了6000字的解读

    万次阅读 多人点赞 2019-10-21 20:03:03
    千万级大表如何优化,这是一个很有技术含量的问题,通常我们的直觉思维都会跳转到拆分或者数据分区,在此我想做一些补充和梳理,想和大家做一些这方面的经验总结,也欢迎大家提出建议。 从一开始脑海里开始也是...
  • 优化算法】简述灰狼优化算法(GWO)原理

    万次阅读 多人点赞 2019-03-25 21:10:34
    系列优化算法简述: OP_1. 简述遗传算法(GA)原理 OP_2 简述灰狼优化算法(GWO)原理 前言: 灰狼优化算法(Grey Wolf Optimizer,GWO)由澳大利亚格里菲斯大学学者 Mirjalili 等人于2014年提出来的一种群智能...
  • Win10必做的性能优化

    万次阅读 多人点赞 2018-09-16 20:39:45
    Windows10系统目前慢慢成为主流的操作系统,win7目前已经不再提供技术支持,到2020年正式退役。...由于win10系统功能变多,系统也变得臃肿,下面就给大家讲讲Windows10必做的优化。 1.关闭家...
  • JMeter(十七):脚本优化之参数化(上)

    万次阅读 2017-10-24 11:09:29
    背景:脚本优化通过关联、参数化、删减无效/无用的请求、增加相关元件来达到脚本符合需求的使用,达到去繁存简的目的。这篇还是以一个业务场景来讲解JMeter那些可以完成参数化的元件。 1、以中国天气官网...
  • 数据库性能优化详解

    万次阅读 多人点赞 2017-02-03 17:38:06
    出处: ...要正确的优化SQL,我们需要快速定位能性的瓶颈点,也就是说快速找到我们SQL主要的开销在哪里?而大多数情况性能最慢的设备会是瓶颈点,如下载时网络速度可能会是瓶颈点,本地复制
  • 数学优化入门:凸优化

    万次阅读 多人点赞 2016-10-18 11:10:50
    做科研时,曾花了段时间学习凸优化,后来发现ML中其应用也非常普遍,想来今后可能还会接触,干脆做个系统的总结,方便以后查询。 博文内容主要参考Boyd(Stanford)的Convex Optimization,配套的slides,以及部分...
  • MySQL优化技巧

    万次阅读 多人点赞 2017-09-10 14:14:00
    MySQL优化三大方向① 优化MySQL所在服务器内核(此优化一般由运维人员完成)。② 对MySQL配置参数进行优化(my.cnf)此优化需要进行压力测试来进行参数调整。③ 对SQL语句以及表优化。MySQL参数优化1:MySQL 默认的最大...
  • 优化算法之粒子群算法(PSO)

    万次阅读 多人点赞 2018-08-03 10:26:45
      粒子群优化算法(PSO:Particle swarm optimization) 是一种进化计算技术(evolutionary computation)。源于对鸟群捕食的行为研究。粒子群优化算法的基本思想:是通过群体中个体之间的协作和信息共享来寻找最优...
  • sql优化的几种方法

    万次阅读 多人点赞 2017-08-17 20:59:55
    在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有需要的可以参考参考。 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上...
  • 何为优化?措施: 对应方法变得更优: 对应的结果更加的好优化: 动词,一种行为方法-----------&gt;目的是获得更好的结果,总之有所改善优化问题的三要素:(1) 决策变量所变:可以改变的量,可以优化的量,...
  • SQL优化最干货总结 - MySQL(2020最新版)

    万次阅读 多人点赞 2020-06-29 16:55:47
    MySQL - SQL优化干货总结(吐血版),别辜负了自己的梦想,欢迎白嫖、点赞、收藏。
  • 此篇博客主要是参考《Android高级进阶》,关于Android开发过程性能优化中的电量优化,布局优化和网络优化做一个记录。
  • 数据库优化 - 实例优化

    千次阅读 2019-10-25 10:30:00
    从网上去搜数据库优化基本都是从SQL层次进行优化的,很少有提及到数据库本身的实例优化。就算有也都是基于某个特定数据库的实例优化,本文涵盖目前市面上所有主流数据库的实例优化(Oralce、MySQL、POSTGRES、达梦)...
  • mysql手册10_SQL优化

    万次阅读 2020-08-19 15:04:41
    mysql手册10_SQL优化 1. 大批量插入数据的优化: 按照主键顺序插入 关闭唯一性校验 导入数据前执行SET UNIQUE_CHECKS=0,关闭唯一性校验 导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验 手动提交事务 ...
  • 本文全面讲解性能优化中的所有知识,献上一份 Android性能优化的详细攻略, 含:优化方向、原因 &amp; 具体优化方案,希望你们会喜欢 文章较长,建议预留较长时间阅读 / 收藏 目录 1. 性能优化...
  • 基于遗传算法的BP神经网络优化算法

    万次阅读 多人点赞 2016-04-10 20:22:41
    遗传算法优化BP神经网络分为BP神经网络结构确定、遗传算法优化和 BP神经网络预测3个部分。其中,BP神经网络结构确定部分根据拟合函数输入输出参数个数确定 BP神经网络结构,这样就可以确定遗传算法的优化参数个数,...
  • Android内存优化之图片优化

    万次阅读 多人点赞 2019-04-08 11:52:23
    关于图片优化,大概如下 为什么要进行图片优化 相信大概刚开始学习Android的时候有过图片过大而直接报错的情况,下面简单介绍一下OOM问题,Android支持的图片格式及图片优化的几种方式 什么是OOM?:Android系统的...
  • MySQL 优化

    千次阅读 多人点赞 2020-04-14 10:44:56
    首先了解什么是优化? 合理安排资源、调整系统参数使MySQL运行更快、更节省资源。 优化是多方面的,包括查询、更新、服务器等。 原则:减少系统瓶颈,减少资源占用,增加系统的反应速度。 数据库 性能参数 ...
  • MySQL版SQL优化

    千人学习 2019-07-06 23:26:29
    本课程通过Centos版的MySQL讲解了SQL优化的一些常见手段。 其中讲解了MySQL的分层、存储引擎等底层逻辑,并讲解了常见的索引优化手段。在讲解时,先通过理论对先关的优化知识进行了铺垫,然后使用实际的案例详细...
  • Android性能优化(二)内存优化

    万次阅读 2020-03-07 22:40:45
    上一篇文章,我总结了一下app启动优化的一些知识。这篇文章,总结一下内存优化相关的一些知识。内存优化,相比于启动优化,可能没那么明显。为什么这么说呢?启动快慢,我们体验一次就能体验出来。而内存增长,我们...
  • MySQL大表优化方案

    万次阅读 多人点赞 2020-11-02 13:51:07
    MySQL数据库本身高度灵活,造成性能不足,严重依赖开发人员的表设计能力以及索引优化能力,在这里给几点优化建议 时间类型转化为时间戳格式,用int类型储存,建索引增加查询效率 建议字段定义not null,null值很难查询...
  • oracle优化:IS NULL的优化 优化方法: 通过nvl(字段i,j),将字段i中为空的数据转化为j, 从而将条件 i is null 转化为 j = nvl(i,j); 转化is null 在所用oracle版本提升明显, 注意:使用时必须确保字段i的数据不包含j! ...
  • 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录 1. 定义 优化处理 应用程序的内存使用、空间占用 2. 作用 避免因不正确使用内存 &amp; 缺乏管理,从而出现 内存泄露(ML)、内存...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 748,508
精华内容 299,403
关键字:

优化