A. 数据库性能优化有哪些措施
1、调整数据结构的设计
这一部分在开发信息系统之前完成,程序员需要考虑是否使用ORACLE数据库的分区功能,对于经常访问的数据库表是否需要建立索引等。
2、调整应用程序结构设计
这一部分也是在开发信息系统之前完成,程序员在这一步需要考虑应用程序使用什么样的体系结构,是使用传统的Client/Server两层体系结构,还是使用Browser/Web/Database的三层体系结构。不同的应用程序体系结构要求的数据库资源是不同的。
3、调整数据库sql语句
应用程序的执行最终将归结为数据库中的SQL语句执行,因此SQL语句的执行效率最终决定了ORACLE数据库的性能。ORACLE公司推荐使用ORACLE语句优化器(OracleOptimizer)和行锁管理器(row-levelmanager)来调整优化SQL语句。
4、调整服务器内存分配
内存分配是在信息系统运行过程中优化配置的,数据库管理员可以根据数据库运行状况调整数据库系统全局区(SGA区)的数据缓冲区、日志缓冲区和共享池的大小;还可以调整程序全局区(PGA区)的大小。需要注意的是,SGA区不是越大越好,SGA区过大会占用操作系统使用的内存而引起虚拟内存的页面交换,这样反而会降低系统。
5、调整硬盘I/O
这一步是在信息系统开发之前完成的。数据库管理员可以将组成同一个表空间的数据文件放在不同的硬盘上,做到硬盘之间I/O负载均衡。
6、调整操作系统参数
例如:运行在UNIX操作系统上的ORACLE数据库,可以调整UNIX数据缓冲池的大小,每个进程所能使用的内存大小等参数。
实际上,上述数据库优化措施之间是相互联系的。ORACLE数据库性能恶化表现基本上都是用户响应时间比较长,需要用户长时间的等待。但性能恶化的原因却是多种多样的,有时是多个因素共同造成了性能恶化的结果,这就需要数据库管理员有比较全面的计算机知识,能够敏感地察觉到影响数据库性能的主要原因所在。另外,良好的数据库管理工具对于优化数据库性能也是很重要的。
一、ORACLE数据库性能优化工具
常用的数据库性能优化工具有:
ORACLE数据库在线数据字典,ORACLE在线数据字典能够反映出ORACLE动态运行情况,对于调整数据库性能是很有帮助的。
操作系统工具,例如UNIX操作系统的vmstat,iostat等命令可以查看到系统系统级内存和硬盘I/O的使用情况,这些工具对于管理员弄清出系统瓶颈出现在什么地方有时候很有用。
SQL语言跟踪工具(SQLTRACEFACILITY),SQL语言跟踪工具可以记录SQL语句的执行情况,管理员可以使用虚拟表来调整实例,使用SQL语句跟踪文件调整应用程序性能。SQL语言跟踪工具将结果输出成一个操作系统的文件,管理员可以使用TKPROF工具查看这些文件。
ORACLEEnterpriseManager(OEM),这是一个图形的用户管理界面,用户可以使用它方便地进行数据库管理而不必记住复杂的ORACLE数据库管理的命令。
EXPLAINPLAN——SQL语言优化命令,使用这个命令可以帮助程序员写出高效的SQL语言。
二、ORACLE数据库的系统性能评估
信息系统的类型不同,需要关注的数据库参数也是不同的。数据库管理员需要根据自己的信息系统的类型着重考虑不同的数据库参数。
1、在线事务处理信息系统(OLTP),这种类型的信息系统一般需要有大量的Insert、Update操作,典型的系统包括民航机票发售系统、银行储蓄系统等。OLTP系统需要保证数据库的并发性、可靠性和最终用户的速度,这类系统使用的ORACLE数据库需要主要考虑下述参数:
数据库回滚段是否足够?
是否需要建立ORACLE数据库索引、聚集、散列?
系统全局区(SGA)大小是否足够?
SQL语句是否高效?
2、数据仓库系统(DataWarehousing),这种信息系统的主要任务是从ORACLE的海量数据中进行查询,得到数据之间的某些规律。数据库管理员需要为这种类型的ORACLE数据库着重考虑下述参数:
是否采用B*-索引或者bitmap索引?
是否采用并行SQL查询以提高查询效率?
是否采用PL/SQL函数编写存储过程?
有必要的话,需要建立并行数据库提高数据库的查询效率
三、SQL语句的调整原则
SQL语言是一种灵活的语言,相同的功能可以使用不同的语句来实现,但是语句的执行效率是很不相同的。程序员可以使用EXPLAINPLAN语句来比较各种实现方案,并选出最优的实现方案。总得来讲,程序员写SQL语句需要满足考虑如下规则:
1、尽量使用索引。试比较下面两条SQL语句:
语句A:SELECTdname,
(SELECTdeptnoFROMemp);
语句B:SELECTdname,deptnoFROMdeptWHERENOTEXISTS
(SELECTdeptnoFROMempWHEREdept.deptno=emp.deptno);
这两条查询语句实现的结果是相同的,但是执行语句A的时候,ORACLE会对整个emp表进行扫描,没有使用建立在emp表上的deptno索引,执行语句B的时候,由于在子查询中使用了联合查询,ORACLE只是对emp表进行的部分数据扫描,并利用了deptno列的索引,所以语句B的效率要比语句A的效率高一些。
2、选择联合查询的联合次序。考虑下面的例子:
SELECTstuffFROMtabaa,tabbb,tabcc
WHEREa.acolbetween:alowand:ahigh
ANDb.bcolbetween:blowand:bhigh
ANDc.ccolbetween:clowand:chigh
ANDa.key1=b.key1
AMDa.key2=c.key2;
这个SQL例子中,程序员首先需要选择要查询的主表,因为主表要进行整个表数据的扫描,所以主表应该数据量最小,所以例子中表A的acol列的范围应该比表B和表C相应列的范围小。
3、在子查询中慎重使用IN或者NOTIN语句,使用where(NOT)exists的效果要好的多。
4、慎重使用视图的联合查询,尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。
5、可以在参数文件中设置SHARED_POOL_RESERVED_SIZE参数,这个参数在SGA共享池中保留一个连续的内存空间,连续的内存空间有益于存放大的SQL程序包。
6、ORACLE公司提供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程“钉”在SQL区中而不被换出内存,程序员对于经常使用并且占用内存很多的存储过程“钉”到内存中有利于提高最终用户的响应时间。
四、CPU参数的调整
CPU是服务器的一项重要资源,服务器良好的工作状态是在工作高峰时CPU的使用率在90%以上。如果空闲时间CPU使用率就在90%以上,说明服务器缺乏CPU资源,如果工作高峰时CPU使用率仍然很低,说明服务器CPU资源还比较富余。
使用操作相同命令可以看到CPU的使用情况,一般UNIX操作系统的服务器,可以使用sar_u命令查看CPU的使用率,NT操作系统的服务器,可以使用NT的性能管理器来查看CPU的使用率。
数据库管理员可以通过查看v$sysstat数据字典中“CPUusedbythissession”统计项得知ORACLE数据库使用的CPU时间,查看“OSUserlevelCPUtime”统计项得知操作系统用户态下的CPU时间,查看“OSSystemcallCPUtime”统计项得知操作系统系统态下的CPU时间,操作系统总的CPU时间就是用户态和系统态时间之和,如果ORACLE数据库使用的CPU时间占操作系统总的CPU时间90%以上,说明服务器CPU基本上被ORACLE数据库使用着,这是合理,反之,说明服务器CPU被其它程序占用过多,ORACLE数据库无法得到更多的CPU时间。
数据库管理员还可以通过查看v$sesstat数据字典来获得当前连接ORACLE数据库各个会话占用的CPU时间,从而得知什么会话耗用服务器CPU比较多。
出现CPU资源不足的情况是很多的:SQL语句的重解析、低效率的SQL语句、锁冲突都会引起CPU资源不足。
1、数据库管理员可以执行下述语句来查看SQL语句的解析情况:
SELECT*FROMV$SYSSTATWHERENAMEIN
('parsetimecpu','parsetimeelapsed','parsecount(hard)');
这里parsetimecpu是系统服务时间,parsetimeelapsed是响应时间,用户等待时间,waitetime=parsetimeelapsed_parsetimecpu
由此可以得到用户SQL语句平均解析等待时间=waitetime/parsecount。这个平均等待时间应该接近于0,如果平均解析等待时间过长,数据库管理员可以通过下述语句
SELECTSQL_TEXT,PARSE_CALLS,EXECUTIONSFROMV$SQLAREA
ORDERBYPARSE_CALLS;
来发现是什么SQL语句解析效率比较低。程序员可以优化这些语句,或者增加ORACLE参数SESSION_CACHED_CURSORS的值。
2、数据库管理员还可以通过下述语句:
SELECTBUFFER_GETS,EXECUTIONS,SQL_TEXTFROMV$SQLAREA;
查看低效率的SQL语句,优化这些语句也有助于提高CPU的利用率。
3、数据库管理员可以通过v$system_event数据字典中的“latchfree”统计项查看ORACLE数据库的冲突情况,如果没有冲突的话,latchfree查询出来没有结果。如果冲突太大的话,数据库管理员可以降低spin_count参数值,来消除高的CPU使用率。
五、内存参数的调整
内存参数的调整主要是指ORACLE数据库的系统全局区(SGA)的调整。SGA主要由三部分构成:共享池、数据缓冲区、日志缓冲区。
1、共享池由两部分构成:共享SQL区和数据字典缓冲区,共享SQL区是存放用户SQL命令的区域,数据字典缓冲区存放数据库运行的动态信息。数据库管理员通过执行下述语句:
select(sum(pins-reloads))/sum(pins)"LibCache"fromv$librarycache;
来查看共享SQL区的使用率。这个使用率应该在90%以上,否则需要增加共享池的大小。数据库管理员还可以执行下述语句:
select(sum(gets-getmisses-usage-fixed))/sum(gets)"RowCache"fromv$rowcache;
查看数据字典缓冲区的使用率,这个使用率也应该在90%以上,否则需要增加共享池的大小。
2、数据缓冲区。数据库管理员可以通过下述语句:
SELECTname,valueFROMv$sysstatWHEREnameIN('dbblockgets','consistentgets','physicalreads');
来查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率=1-(physicalreads/(dbblockgets+consistentgets))。
这个命中率应该在90%以上,否则需要增加数据缓冲区的大小。
3、日志缓冲区。数据库管理员可以通过执行下述语句:
selectname,valuefromv$sysstatwherenamein('redoentries','redologspacerequests');
查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率:
申请失败率=requests/entries,申请失败率应该接近于0,否则说明日志缓冲区开设太小,需要增加ORACLE数据库的日志缓冲区。
昆明北大青鸟java培训班转载自网络如有侵权请联系我们感谢您的关注谢谢支持
B. 数据库性能优化有哪些措施
1、调整数据结构的设计。这一部分在开发信息系统之前完成,程序员需要考虑是否使用ORACLE数据库的分区功能,对于经常访问的数据库表是否需要建立索引等。
2、调整应用程序结构设计。这一部分也是在开发信息系统之前完成,程序员在这一步需要考虑应用程序使用什么样的体系结构,是使用传统的Client/Server两层体系结构,还是使用Browser/Web/Database的三层体系结构。不同的应用程序体系结构要求的数据库资源是不同的。
3、调整数据库SQL语句。应用程序的执行最终将归结为数据库中的SQL语句执行,因此SQL语句的执行效率最终决定了ORACLE数据库的性能。ORACLE公司推荐使用ORACLE语句优化器(Oracle Optimizer)和行锁管理器(row-level manager)来调整优化SQL语句。
4、调整服务器内存分配。内存分配是在信息系统运行过程中优化配置的,数据库管理员可以根据数据库运行状况调整数据库系统全局区(SGA区)的数据缓冲区、日志缓冲区和共享池的大小;还可以调整程序全局区(PGA区)的大小。需要注意的是,SGA区不是越大越好,SGA区过大会占用操作系统使用的内存而引起虚拟内存的页面交换,这样反而会降低系统。
5、调整硬盘I/O,这一步是在信息系统开发之前完成的。数据库管理员可以将组成同一个表空间的数据文件放在不同的硬盘上,做到硬盘之间I/O负载均衡。
6、调整操作系统参数,例如:运行在UNIX操作系统上的ORACLE数据库,可以调整UNIX数据缓冲池的大小,每个进程所能使用的内存大小等参数。
数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各种数据管理的方式。数据库有很多种类型,从最简单的存储有各种数据的表格到能够进行海量数据存储的大型数据库系统都在各个方面得到了广泛的应用。
在信息化社会,充分有效地管理和利用各类信息资源,是进行科学研究和决策管理的前提条件。数据库技术是管理信息系统、办公自动化系统、决策支持系统等各类信息系统的核心部分,是进行科学研究和决策管理的重要技术手段。
在经济管理的日常工作中,常常需要把某些相关的数据放进这样的“仓库”,并根据管理的需要进行相应的处理。
例如,企业或事业单位的人事部门常常要把本单位职工的基本情况(职工号、姓名、年龄、性别、籍贯、工资、简历等)存放在表中,这张表就可以看成是一个数据库。有了这个"数据仓库"我们就可以根据需要随时查询某职工的基本情况,也可以查询工资在某个范围内的职工人数等等。这些工作如果都能在计算机上自动进行,那我们的人事管理就可以达到极高的水平。此外,在财务管理、仓库管理、生产管理中也需要建立众多的这种"数据库",使其可以利用计算机实现财务、仓库、生产的自动化管理。
(2)存储函数的性能优化扩展阅读
数据库,简单来说是本身可视为电子化的文件柜--存储电子文件的处所,用户可以对文件中的数据进行新增、截取、更新、删除等操作。
数据库指的是以一定方式储存在一起、能为多个用户共享、具有尽可能小的冗余度的特点、是与应用程序彼此独立的数据集合。
在经济管理的日常工作中,常常需要把某些相关的数据放进这样的"仓库",并根据管理的需要进行相应的处理。
例如,企业或事业单位的人事部门常常要把本单位职工的基本情况(职工号、姓名、年龄、性别、籍贯、工资、简历等)存放在表中,这张表就可以看成是一个数据库。有了这个"数据仓库"我们就可以根据需要随时查询某职工的基本情况,也可以查询工资在某个范围内的职工人数等等。这些工作如果都能在计算机上自动进行,那我们的人事管理就可以达到极高的水平。此外,在财务管理、仓库管理、生产管理中也需要建立众多的这种"数据库",使其可以利用计算机实现财务、仓库、生产的自动化管理。
C. 存储性能优化 MMKV源码解析
好久没有更新常用的第三方库了。让我们来聊聊MMKV这个常用的第三方库。MMKV这个库是做什么的呢?他本质上的定位和sp有点相似,经常用于持久化小数据的键值对。其速度可以说是当前所有同类型中速度最快,性能最优的库。
它的最早的诞生,主要是因为在微信iOS端有一个重大的bug,一个特殊的文本可以导致微信的iOS端闪退,而且还出现了不止一次。为了统计这种闪退的字符出现频率以及过滤,但是由于出现的次数,发现原来的键值对存储组件NSUserDefaults根本达不到要求,会导致cell的滑动卡顿。
因此iOS端就开始创造一个高新性能的键值对存储组件。于此同时,Android端SharedPreferences也有如下几个缺点:
因此Android也开始复用iOS的MMKV,而后Android有了多进程的写入数据的需求,Android组又在这个基础上进行改进。
这里是官方的性能的比较图:
能看到mmkv比起我们开发常用的组件要快上数百倍。
那么本文将会从源码角度围绕MMKV的性能为什么会如此高,以及SharePrefences为什么可能出现ANR的原因。
请注意下文是以MMKV 1.1.1版本源码为例子分析。如果遇到什么问题欢迎来到本文 https://www.jianshu.com/p/c12290a9a3f7 互相讨论。
老规矩,先来看看MMKV怎么使用。mmkv其实和SharePrefences一样,有增删查改四种操作。
MMKV作为一个键值对存储组件,也对了存储对象的序列化方式进行了优化。常用的方式比如有json,Twitter的Serial。而MMKV使用的是Google开源的序列化方案:Protocol Buffers。
Protocol Buffers这个方案比起json来说就高级不少:
使用方式可以阅读下面这篇文章: https://www.jianshu.com/p/e8712962f0e9
下面进行比较几个对象序列化之间的要素比较
而MMKV就是看重了Protocol Buffers的时间开销小,选择Protocol Buffers进行对象缓存的核心。
使用前请初始化:
当然mmkv除了能够写入这些基本类型,只要SharePrefences支持的,它也一定能够支持。
同上,每一个key读取的数据类型就是decodexxx对应的类型名字。使用起来十分简单。
能够删除单个key对应的value,也能删除多个key分别对应的value。containsKey判断mmkv的磁盘缓存中是否存在对应的key。
mmkv和SharePrefences一样,还能根据模块和业务划分对应的缓存文件:
这里创建了一个id为a的实例在磁盘中,进行数据的缓存。
当需要多进程缓存的时候:
MMKV可以使用Ashmem的匿名内存进行更加快速的大对象传输:
进程1:
最重要的一点,mmkv把SharePrefences的缓存迁移到mmkv中,之后的使用就和SharePrefences一致。
这里就是把SharedPreferences的myData数据迁移到mmkv中。当然如果我们需要保持SharePreferences的用法不变需要自己进行自定义一个SharePreferences。
mmkv的用法极其简单,接下来我们关注他的原理。
首先来看看MMKV的初始化。
能看到实际上initialize分为如下几个步骤:
能看到其实就是做这个判断。由于此时设置的是libc++的打包方式。此时BuildConfig.FLAVOR就是StaticCpp,就不会加载c++_shared。当然,如果我们已经使用了c++_shared库,则没有必要打包进去,使用defaultPublishConfig "SharedCppRelease"会尝试的查找动态链接库_shared。这样就能少2M的大小。
请注意一个前提的知识,jni的初始化,在调用了 System.loadLibrary之后,会通过dlopen把so加载到内存后,调用dlsym,调用jni中的JNI_OnLoad方法。
实际上这里面做的事情十分简单:
能从这些native方法中看到了所有MMKV的存储方法,设置支持共享内存ashemem的存储,支持直接获取native malloc申请的内存
接下来就是MMKV正式的初始化方法了。
这个方法实际上调用的是pthread_once方法。它一般是在多线程环境中,根据内核的调度策略,选择一个线程初始化一次的方法。
其实这里面的算法很简单:
defaultMMKV此时调用的是getDefaultMMKV这个native方法,默认是单进程模式。从这里的设计都能猜到getDefaultMMKV会从native层实例化一个MMKV对象,并且让实例化好的Java层MMKV对象持有。之后Java层的方法和native层的方法一一映射就能实现一个直接操作native对象的Java对象。
我们再来看看MMKV的mmkvWithID。
感觉上和defaultMMKV有点相似,也是调用native层方法进行初始化,并且让java层MMKV对象持有native层。那么我们可否认为这两个实例化本质上在底层调用同一个方法,只是多了一个id设置呢?
可以看看MMKV.h文件:
这里就能看到上面的推测是正确的,只要是实例化,最后都是调用mmkvWithID进行实例化。默认的mmkv的id就是mmkv.default。Android端则会设置一个默认的page大小,假设4kb为例子。
所有的mmkvID以及对应的MMKV实例都会保存在之前实例化的g_instanceDic散列表中。其中mmkv每一个id对应一个文件的路径,其中路径是这么处理的:
如果发现对应路径下的mmkv在散列表中已经缓存了,则直接返回。否则就会把相对路径保存下来,传递给MMKV进行实例化,并保存在g_instanceDic散列表中。
我们来看看MMKV构造函数中几个关键的字段是怎么初始化。
mmkvID就是经过md5后对应缓存文件对应的路径。
能看到这里是根据当前的mode初始化id,如果不是ashmem匿名共享内存模式进行创建,则会和上面的处理类似。id就是经过md5后对应缓存文件对应的路径。
注意这里mode设置的是MMKV_ASHMEM,也就是ashmem匿名共享内存模式则是如下创建方法:
实际上就是在驱动目录下的一个内存文件地址。
接下来,在构造函数中使用了共享的文件锁进行保护后,调用loadFromFile进一步的初始化MMKV内部的数据。
我们大致的了解MMKV中每一个字段的负责的职责,但是具体如何进行工作下文都会解析。
在这里面我们遇到了看起来十分核心的类MemoryFile,它的名字有点像 Ashmem匿名共享内存 一文中描述过Java层的映射的匿名内存文件。
我们先来看看MemoryFile的初始化。
MemeoryFile分为两个模式进行初始化:
这里的处理很简单:
能看到此时将会调用mmap系统调用,通过设置标志位可读写,MAP_SHARED的模式进行打开。这样就file就在在内核中映射了一段4kb内存,以后访问文件可以不经过内核,直接访问file映射的这一段内存。
关于mmap系统调用的源码解析可以看这一篇 Binder驱动的初始化 映射原理 。
能看到在这个过程中实际上还是通过ftruncate进行扩容,接着调用zeroFillFile,先通过lseek把指针移动当前容量的最后,并把剩余的部分都填充空数据'\0'。最后映射指向的地址是有效的,会先解开后重新进行映射。
为什么要做最后这个步骤呢?如果阅读过我解析的mmap的源码一文,实际上就能明白,file使用MAP_SHARED的模式本质上是给file结构体绑定一段vma映射好的内存。ftruncate只是给file结构体进行了扩容,但是还没有对对应绑定虚拟内存进行扩容,因此需要解开一次映射后,重新mmap一次。
MMKV在如果使用Ashmem模式打开:
接下来loadFromFile 这个方法可以说是MMKV的核心方法,所有的读写,还是扩容都需要这个方法,从映射的文件内存,缓存到MMKV的内存中。
进入到这个方法后进行如下的处理:
在这里,遇到了一个比较有歧义的字段m_version ,从名字看起来有点像MMKV的版本号。其实它指代的是MMKV当前的状态,由一个枚举对象代表:
注意m_vector是一个长度16的char数组。其实很简单,就是把文件保存的m_vector获取16位拷贝到m_metaInfo的m_vector中。因为aes的加密必须以16的倍数才能正常运作。
初始化分为这6点,我们从最后三点开始聊聊MMKV的初始化的核心逻辑。我们还需要开始关注MMKV中内存存储的结构。
能看到首先从m_file获取映射的指针地址,往后读取4位数据。这4位数据就是actualSize 真实数据。但是如果是m_metaInfo的m_version 大于等于3,则获取m_metaInfo中保存的actualSize。
其校验的手段,是通过比较m_metaInfo保存的crcDigest和从m_file中读取的crcDigest进行比较,如果一致说明数据无误,则返回true,设置loadFromFile为true。
其实这里面只处理m_metaInfo的m_version的状态大于等于3的状态。我们回忆一下,在readActualSize方法中,把读取当前存储的数据长度,分为两个逻辑进行读取。如果大于等于3,则从m_metaInfo中获取。
crc校验失败,说明我们写入的时候发生异常。需要强制进行recover恢复数据。
首先要清除crc校验校验了什么东西:
MMKV做了如下处理,只处理状态等级在MMKVVersionActualSize情况。这个情况,在m_metaInfo记录上一次MMKV中的信息。因此可以通过m_metaInfo进行校验已经存储的数据长度,进而更新真实的已经记录数据的长度。
最后读取上一次MMKV还没有更新的备份数据长度和crc校验字段,通过writeActualSize记录在映射的内存中。
如果最后弥补的校验还是crc校验错误,最后会回调onMMKVCRCCheckFail这个方法。这个方法会反射Java层实现的异常处理策略
如果是OnErrorRecover,则设置loadFromFile和needFullWriteback都为true,尽可能的恢复数据。当然如果OnErrorDiscard,则会丢弃掉所有的数据。
D. 存储体系如何体现不同性能资源和优化组合
不同性能资源组合优化思维,化整为0的存储思维:数据存储能力是现代计算机的重要能力。人们对存储器的要求是:存储容量要足够大(越大越好),存储速度要足够快(能够匹配CPU的运算速度)、存储时间要足够长(越长越好)、价格要足够低(越低越好)。但满足上述要求的存储器是理想化的,因此现实中出现了各种性能的存储器。典型的存储器有:寄存器、随机存取存储器RAM、只读存储器ROM、高速缓冲存储器Cache、硬盘及其它外存。这些存储器构成一个存储体系,其中外存不与CPU直接交换信息,内存与CPU直接交换信息。因此,内存就好像外存的一个“临时缓冲区”。外存速度慢,以存储块为单位进行读写(一个存储块为一个扇区或其倍数),可以一次将更多的信息读写到内存,再被CPU处理。内存速度快,可与CPU中的寄存器按存储单元/存储字为单位交换信息,或者内存经过Cache,以Cache为缓冲区与CPU的寄存器交换信息。这样“以批量换取速度、以空间换取时间”来实现存储器与CPU之间速度的匹配,可使用户感觉到读写速度很快同时容量又很大。相关资料:不同性能资源组合优化思维属于一种计算机的里面的一种相应的这种思维。就是通过这种相关的这种一些不同的这种组合,然后找到他这种相关的这种优化的特点,也就是说这个先进行相应的这种处理,然后再找到他的优点。这就要求他们能够在这种复杂的环境下都能够进行执行,这样的不同的这种程序不同的相关的这种组合进行统一处理,通过这种控制调度就是可以实现这种资源整合。
E. 教程 | Excel性能优化方法(二)
方法六
允许额外数据
如果经常向工作表中添加多行或多列数据,则需要找出一种方法,使Excel 公式自动引用新数据区域,而不是每次都尝试查找并更改公式。为此,可以在公式中使用远超出当前数据边界的较大区域。然而,在某些情况下,这可能会导致无效计算而且很难维护,这是因为删除行和列可能会在你不注意的情况下减小区域。
方法七
使用结构化表引用
从 Excel 2007 开始,可以使用结构化表引用,此类引用可随所引用表大小的增加或减小自动扩大和缩小。此解决方案有诸多优点:
方法八
使用整列引用和整行引用
例如 $A:$A。此引用返回 A 列中的所有行。因此,可以根据需要添加任意数量的数据,引用始终都包含这些数据。此解决方案包含以下优点和缺点:
方法九
用动态区域
通过在已命名区域的定义中使用 OFFSET 或 INDEX 和 COUNTA 函数,可以使已命名区域引用的区域动态扩大和缩小。例如,使用下列公式之一创建已定义名称:
在公式中使用动态区域名称时,它会自动扩大以包含新条目。对于动态区域,使用 INDEX 公式通常比使用 OFFSET 公式更可取,因为 OFFSET 的缺点是它是一个可变函数,每次重新计算都要对其进行计算。性能下降是因为动态区域公式中的 COUNTA 函数必须检查多个行。可以通过将公式的 COUNTA 部分存储在单独单元格或已定义的名称中,然后在动态区域内引用单元格或名称来最大程度减少性能下降:
还可以使用 INDIRECT 等函数来构造动态区域,但 INDIRECT 是可变函数,且始终计算单线程。动态区域具有以下优点和缺点:
方法十
缩短查找计算时间
在 Office 365 版本 1809 和更高版本中,在从相同表区域查找多个列(或使用 HLOOKUP 查找行)时,Excel 的 VLOOKUP、HLOOKUP 和 MATCH 对未排序数据进行完全匹配要比以往快得多。也就是说,对于早期的 Excel 版本,查找仍然是常见的重要计算障碍。幸运的是,有许多方法可以改进缩短计算时间。如果使用完全匹配选项,则函数的计算时间与找到匹配之前扫描的单元格数量成正比。对于在较大区域进行查找,这一时间可能很长。对排序数据使用 VLOOKUP、HLOOKUP 和 MATCH 的近似匹配选项的查找时间很短,并且不会根据所查找的区域长度显着增加。特征与二进制搜索相同。
F. SQL Server 优化存储过程的方法有哪些
优化存储过程有很多种方法,下面介绍最常用的7种。
1.使用SET NOCOUNT ON选项
我们使用SELECT语句时,除了返回对应的结果集外,还会返回相应的影响行数。使用SET NOCOUNT ON后,除了数据集就不会返回额外的信息了,减小网络流量。
2.使用确定的Schema
在使用表,存储过程,函数等等时,最好加上确定的Schema。这样可以使SQL Server直接找到对应目标,避免去计划缓存中搜索。而且搜索会导致编译锁定,最终影响性能。比如select * from dbo.TestTable比select * from TestTable要好。from TestTable会在当前Schema下搜索,如果没有,再去dbo下面搜索,影响性能。而且如果你的表是csdn.TestTable的话,那么select * from TestTable会直接报找不到表的错误。所以写上具体的Schema也是一个好习惯。
3.自定义存储过程不要以sp_开头
因为以sp_开头的存储过程默认为系统存储过程,所以首先会去master库中找,然后在当前数据库找。建议使用USP_或者其他标识开头。
4.使用sp_executesql替代exec
原因在Inside Microsoft SQL Server 2005 T-SQL Programming书中的第四章Dynamic SQL里面有具体描述。这里只是简单说明一下:sp_executesql可以使用参数化,从而可以重用执行计划。exec就是纯拼SQL语句。
5.少使用游标
可以参考Inside Microsoft SQL Server 2005 T-SQL Programming书中的第三章Cursors里面有具体描述。总体来说,SQL是个集合语言,对于集合运算具有较高的性能,而Cursors是过程运算。比如对一个100万行的数据进行查询,游标需要读表100万次,而不使用游标只需要少量几次读取。
6.事务越短越好
SQL Server支持并发操作。如果事务过多过长,或是隔离级别过高,都会造成并发操作的阻塞,死锁。此时现象是查询极慢,同时cup占用率极低。
7.使用try-catch来处理错误异常
SQL Server 2005及以上版本提供对try-catch的支持,语法为:
begin try
----your code
end try
begin catch
--error dispose
end catch
一般情况可以将try-catch同事务结合在一起使用。
begin try
begin tran
--select
--update
--delete
--…………
commit
end try
begin catch
--if error
rollback
end catch
====================== 分割线 =======================
‘自己的一些调优经验’
1. 少使用游标是个很好的建议,为此,我自己也遇到过一些事故,是游标所造成的,由于,游标是逐行逐行操作的,当记录较多时,经常会遇到超时的情况。
2. 多表join做查询时,查询的字段尽量不要使用case when then else end的语法,或者使用用户函数,例如:
select (case when fType=1 then '是' else '否' end) as fTypeName, dbo.F_GetFullName(fID) as fFullName from Table1 inner join Table2……
当两个表的数据量非常大时,你可以在查询分析器中明显感觉到:直接查询fType和fID与查询上面两个字段的速度,很可能使用了一个case when then就导致超时。
针对这种情况,可以分两种做法:
第一,把一些简单的转换可以放在程序中完成。
第二,如果需要通过ID查询全名或者全称,类似的,可以创建好视图,直接查视图,或者,先把所有的fFullName查出来放到临时表中,直接join临时表(如果这个数据不是很多的话),获得fFullName。
3. 少使用一些嵌套的查询,用临时表缓存中间数据,例如:
select * from Table1
inner join (
select count(1) as count, Table2.ID2 from Table2 inner join Table3 on ID2=ID3 group by Table2.ID2
) as t1 on t1.ID1 = Table1.ID1
我曾经遇到这样情况,上面的语句是那种情况的简化版本,把其他不影响结果的表格都去掉了,发现一个奇怪的现象:嵌套查询的结果集并不大,大约就200多行,Table1有6w条记录,结果,这个查询语句超时,查询分析器中执行2分钟也得不到结果。
后来,这样一改,就Ok了,3秒出结果:
select count(1) as count, Table2.ID2 into #temp from Table2 inner join Table3 on ID2=ID3 group by Table2.ID2
select * from Table1
inner join #temp as t1 on t1.ID1 = Table1.ID1
这样一改,效率提升了几十倍,猜想:可能是嵌套的查询是动态的,每一行的join可能都需要先执行嵌套的查询,从而导致效率极差。
所以,如果查询足够复杂,join多个表,需要连接多个通过group by求和、求平均数等运算计算出来的中间数据,那么,不妨多使用临时表缓存中间数据。
4. 还有一些是必须遵守的一些默认规则,比如:
先过滤后连接。
查询的字段最要不要用“*”,指定需要用的字段,减少网络流量。
‘总结’
对于性能的追求是没有极限的,做到你所能做到的,这是一个很好的习惯。
有些业务逻辑放在存储过程中处理比较方便,而有些业务逻辑交给程序来处理,同样会提升系统整体的效率,看实际情况而定。
总之,尽可能减少这些容易引发性能问题的隐患,系统就会跑得更稳定更有效率,一切从小细节做起。
G. 教程 | Excel性能优化方法(三)
01
使用 INDEX 和 MATCH 或 OFFSET 而不是 VLOOKUP
虽然 VLOOKUP 比 MATCH 和 INDEX,或 OFFSET 组合的速度稍快(大约快 5%)、更简单,并使用更少的内存,但 MATCH 和 INDEX 所提供的额外灵活性通常可以显着节省时间。例如,可以将完全 MATCH 的结果存储在单元格中,并在几个 INDEX 语句中重用。INDEX 函数是快速运行的不变函数,它可以加快重新计算的速度。 OFFSET 函数的运行速度也很快;但它是可变函数,因此有时会显着增加处理计算链所需的时间。可轻松将 VLOOKUP 转换为 INDEX 和 MATCH。以下两个语句返回相同结果:
02
SORT的应用
由于完全匹配查找可能很慢,因此可以考虑使用以下选项来提高性能:
03
对缺少值的排序数据使用两个查找
对于在数行内执行的查找,两个近似匹配显着快于一个完全匹配。 (分界点是大约 10-20 行。)
如果可以对数据排序,但由于不能确定要查找的值是否位于查找范围内而仍无法使用近似匹配,则可以使用以下公式:
公式第一部分的运作方式是对查找列本身执行近似查找
可以使用以下公式检查从查找列得到的结果是否与查找值相同(在这种情况下,你有一个完全匹配项):
如果此公式返回“True”,则找到了完全匹配项,所以可以再次执行近似查找,但这次从列中返回所需的结果。
如果从查找列得到的结果与查找值不匹配,则表示它是缺失值,公式将返回“notexist”。
注意,如果查找的值小于列表中的最小值,则会收到错误。可以使用 IFERROR 来处理此错误,或者向列表添加一个小的测试值。
04
对于缺少值的未排序数据,使用 IFERROR 函数
如果必须对未排序数据使用完全匹配查找,但是不能确定查找值是否存在,通常必须处理找不到匹配项时返回的 #N/A。从 Excel 2007 开始,可以使用 IFERROR 函数,该函数既快又简单。
在早期版本中,一个简单但较慢的方法是使用包含两个查找的 IF 函数。
如果使用完全 MATCH 一次,将结果存储在单元格中,然后在执行 INDEX 之前测试结果,则可以避免双重完全查找。
如果无法使用两个单元格,则使用 COUNTIF。它通常比完全匹配查找速度快。
05
使用 MATCH 和 INDEX 对多个列进行完全匹配查找
通常可以多次重复使用存储的完全 MATCH。例如,如果要对多个结果列执行完全查找,则可以使用一个 MATCH 和多个 INDEX 语句(而不是多个 VLOOKUP 语句)来节省时间。为 MATCH 添加一个额外的列来存储结果 ( stored_row ),并对每个结果列使用以下语句:
或者,可以在数组公式中使用 VLOOKUP。(必须使用 Ctrl+-Shift+Enter 输入数组公式。Excel 将添加 { and },以显示这是一个数组公式)。
H. Sql sever怎么优化存储过程。。大概步骤
1、精减变量,排除重复
2、优化SQL语句,将效率低的语句找出,尽量不用查询全部、嵌套等SQL
3、将重复语句尽量用动态语句实现
4、尽量少用SQL直接计算,能用函数就用函数
等等
具体还是需要根据业务需求调整
I. 教程 | Excel性能优化方法(四)
01
对一组连续的行或列使用 INDEX
还可以从一个查找操作返回多个单元格。要查找多个连续的列,可以使用数组公式中的 INDEX 函数一次返回多个列(使用 0 作为列号)。还可以使用 INDEX 函数一次返回多个行。
这将从之前的 MATCH 语句创建的存储行返回列 A 到列 J
02
使用子集区域进行多索引查找
在大型工作表中,可能经常需要使用多个索引来进行查找,例如查找某个国家/地区的产品量。为此,可以连接索引并使用连接的查找值执行查找。然而,有两个原因会导致其效率低下:
计算查找的子集区域通常更有效(例如,通过查找国家/地区的第一行和最后一行,然后在该子级区域内查找产品)。
03
考虑三维查找选项
除行和列外,若还要查找要使用的表,则可以使用以下方法,这些方法重点处理如何使 Excel 查找或选择表。如果要查找的每个表(第三维)都存储为一组已命名结构化表、区域名称或存储为表示区域的文本字符串表,则可以使用 CHOOSE 或 INDIRECT 函数。使用 CHOOSE 和区域名称是一种有效方法。 CHOOSE 是不可变函数,但最适用于相对较少的表。此示例动态使用 TableLookup_Value 来选择要用于查找表的区域名称 ( TableName1, TableName2, ... )。
下面的示例使用 INDIRECT 函数和 TableLookup_Value 动态创建要用于查找表的工作表名称。这种方法的优点是简单,能够处理大量表。因为 INDIRECT 是可变的单线程函数,所以即使没有数据发生变化,查找也是每次计算时计算的单线程。使用此方法速度较慢。
还可以使用 VLOOKUP 函数查找要用于表的工作表名称或文本字符串,然后使用 INDIRECT 函数将结果文本转换为区域。
另一方法是将所有表聚合到一个大型表中,该表包含另一标识各个表的列。然后可以使用前面的示例中所示的多索引查找方法。
04
使用通配符查找
MATCH、VLOOKUP 和 HLOOKUP 函数允许你在按字母顺序完全匹配的情况下使用通配符 ? (任何单个字符)和 *(没有字符或任意数量的字符)。有时,可使用此方法避免多个匹配项。
05
优化数组公式和 SUMPRODUCT
数组公式和 SUMPRODUCT 函数功能强大,但必须谨慎处理。单个数组公式可能需要多次计算。优化数组公式计算速度的关键在于,确保尽可能减少在数组公式中计算的单元格和表达式的数量。请记住,数组公式与可变公式有点相似:如果它引用的任何一个单元格发生更改、可变或者经过重新计算,则数组公式会计算该公式中的所有单元格并计算执行计算所需的所有虚拟单元格。要优化数组公式的计算速度,请执行以下操作:将数组公式中的表达式和区域引用提取到单独的辅助列和行中。这样可以更好地利用 Excel 中的智能重新计算过程。不要引用完整行,或引用超出需要的行和列。数组公式被迫计算公式中的所有单元格引用,即使单元格为空或未使用。从 Excel 2007 开始,有 100 万行可用,引用整个列的数组公式的计算速度极其缓慢。从 Excel 2007 开始,如果可以,请使用结构化引用来最大程度地减少数组公式计算的单元格数。在 Excel 2007 之前的版本中,尽可能使用动态区域名称。尽管它们可变,但这是值得的,因为它们最大程度缩小了区域大小。注意同时引用行和列的数组公式:这将强制计算矩形区域。尽可能使用 SUMPRODUCT;它比等效的数组公式速度稍微快一点。