首页 文章 精选 留言 我的

精选列表

搜索[小程序·即时通信 IM],共10028篇文章
优秀的个人博客,低调大师

MS SQL巡检系列——检查外键字段是否缺少索引

原文: MS SQL巡检系列——检查外键字段是否缺少索引 前言感想:一时兴起,突然想写一个关于MS SQL的巡检系列方面的文章,因为我觉得这方面的知识分享是有价值,也是非常有意义的。一方面,很多经验不足的人,对于巡检有点茫然,不知道要从哪些方面巡检,另外一方面,网上关于MS SQL巡检方面的资料好像也不是特别多。写这个系列只是一个分享,自己的初衷是一个知识梳理、总结提炼过程,有些知识和脚本也不是原创,文章很多地方融入了自己的一些想法和见解的,不足和肤浅之处肯定也非常多,抛砖引玉,也希望大家提意见和建议、补充,指正其中的不足之处。Stay Hungry Stay Foolish! MS SQL巡检系列——检查重复索引 MS SQL巡检系列——检查外键字段是否缺少索引 MS SQL巡检系列——检查数据库上一次DBCC CHECKDB的时间 对于绝大部分情况,外键字段都有必要建立对应的索引(注意,外键约束并不会自动建立索引),关于外键字段为什么要建立索引?下面从几个简单的例子来分析一下。我们先准备测试环境数据。 CREATETABLE PRIMARY_TB ( PRODUCT_CD VARCHAR(12) , PRODUCT_DATE DATE , PRODUCT_DESC VARCHAR(120) , CONSTRAINT PK_PRIMARY_TB PRIMARYKEYCLUSTERED (PRODUCT_CD) ); SET NOCOUNT ON; GO DECLARE @IndexINT=1; BEGINTRAN WHILE @Index <= 3000 BEGIN INSERT INTO dbo.PRIMARY_TB SELECT'Prd' + CAST(@IndexASVARCHAR(4)), GETDATE() - CEILING(RAND()*200), 'production description' + CAST(@IndexASVARCHAR(4)); SET @Index +=1; END COMMIT; CREATETABLE FK_TB ( FK_ID INTIDENTITY(1,1), SALES_REGION VARCHAR(32), SALES_CITY VARCHAR(32), PRODUCT_CD VARCHAR(12), SALIES_SUM INT, CONSTRAINT PK_FK_TB PRIMARYKEYCLUSTERED (FK_ID) ) GO ALTERTABLE [dbo].[FK_TB] WITHCHECKADD CONSTRAINT [FK_PRIMARY_TB_PRODUCT_CD] FOREIGNKEY([PRODUCT_CD]) REFERENCES [dbo].[PRIMARY_TB] ([PRODUCT_CD]) ON DELETECASCADE; GO SET NOCOUNT ON; GO DECLARE @IndexINT=1; BEGINTRAN WHILE @Index <=1000000 BEGIN INSERT INTO FK_TB SELECT'REGION'+CAST(CEILING(RAND()*20) ASVARCHAR(2)), CAST(CEILING(RAND()*300) ASVARCHAR(3)),'Prd'+ CAST(CEILING(RAND()*3000) ASVARCHAR(8)),CEILING(RAND()*100000); SET @Index +=1; END COMMIT; UPDATESTATISTICS dbo.PRIMARY_TB WITH FULLSCAN; UPDATESTATISTICS dbo.FK_TB WITH FULLSCAN; GO 1: 外键字段建立索引,在主表与子表JOIN操作时能提高性能,减少IO操作。 DBCC DROPCLEANBUFFERS; GO DBCC FREEPROCCACHE; GO SETSTATISTICS IO ON; SETSTATISTICSTIMEON; SELECT p.PRODUCT_CD , p.PRODUCT_DATE , f.SALES_REGION , f.SALES_CITY , f.SALIES_SUM FROM dbo.PRIMARY_TB p INNERJOIN dbo.FK_TB f ON p.PRODUCT_CD = f.PRODUCT_CD WHERE p.PRODUCT_CD ='Prd131'; SETSTATISTICS IO OFF; SETSTATISTICSTIMEOFF; 如下截图所示,如果外键字段缺少索引,这两个表关联查询时,子表就会走扫描(此处测试是聚集索引扫描),如果子表非常大(例如此处案例所示),IO开销就比较大。 我们对外键约束字段PRODUCT_CD建立下面非聚集索引IDX_FK_TB,然后对比两者的执行计划和IO开销 CREATEINDEX IDX_FK_TB ON dbo.FK_TB(PRODUCT_CD); DBCC DROPCLEANBUFFERS; GO DBCC FREEPROCCACHE; GO SETSTATISTICS IO ON; SETSTATISTICSTIMEON; SELECT p.PRODUCT_CD , p.PRODUCT_DATE , f.SALES_REGION , f.SALES_CITY , f.SALIES_SUM FROM dbo.PRIMARY_TB p INNERJOIN dbo.FK_TB f ON p.PRODUCT_CD = f.PRODUCT_CD WHERE p.PRODUCT_CD ='Prd131' SETSTATISTICS IO OFF; SETSTATISTICSTIMEOFF; 你会发现执行计划从原来的聚集索引扫描(Clustered Index Scan)变成了索引查找(Index Seek),IO的减少也是非常明显的。因为这里仅仅是测试数据,复杂的生产环境,性能的提升有可能比这更加明显。 2:如果外键约束为CASCADE(on update/delete)时,则当修改被引用行(referenced row)时,所有引用行(referencing rows )也必须修改(更新或级联删除)。外键列上的索引能减小锁的粒度和范围,从而提高效率和性能。如下所示: 我们先看看缺少索引的情况。 DROPINDEX IDX_FK_TB ON dbo.FK_TB; DBCC DROPCLEANBUFFERS; GO DBCC FREEPROCCACHE; GO SETSTATISTICS IO ON; SETSTATISTICSTIMEON; DELETEFROM dbo.PRIMARY_TB WHERE PRODUCT_CD IN ('Prd132','Prd133') GO SETSTATISTICS IO OFF; SETSTATISTICSTIMEOFF; CREATEINDEX IDX_FK_TB ON dbo.FK_TB(PRODUCT_CD); GO DBCC DROPCLEANBUFFERS; GO DBCC FREEPROCCACHE; GO SETSTATISTICS IO ON; SETSTATISTICSTIMEON; DELETEFROM dbo.PRIMARY_TB WHERE PRODUCT_CD IN ('Prd134','Prd135') GO SETSTATISTICS IO OFF; SETSTATISTICSTIMEOFF; 3:如果外键关系为NO ACTION(on update/delete)时,那么被引用的行不能被删除,因为这个操作会导致引用行变成“孤立”。删除之前,数据库会为了有效地查找、定位行,外键列上创建索引也非常有帮助。 上面肤浅的构造了简单案例,并对比外键约束字段拥有索引和缺少索引时,SQL的执行计划和IO的差异,那么接下来,我们进入正题,巡检的时候,我们必须通过脚本找到数据库里面外键字段没有索引的相关表和信息,并生成对应的创建索引的脚本。如下所示。 /* One or more tables found, with foreign key constraint defined but no supporting indexes created on the foreign key columns. SQL Server doesnt put an index on foreign key columns by default and indexing foreign key fields in referencing tables is not required. Foreign key columns usage must evaluated to determine whether or not indexing this column will help up increase the current workloads performance by enhancing join performance, reducing table locking (for full table scans) while cascading updates and deletes, etc. */ ; WITH FKTable AS ( SELECT SCHEMA_NAME(po.schema_id) AS'parent_schema_name' , OBJECT_NAME(fkc.parent_object_id) AS'parent_table_name' , OBJECT_NAME(constraint_object_id) AS'constraint_name' , SCHEMA_NAME(ro.schema_id) AS'referenced_schema' , OBJECT_NAME(referenced_object_id) AS'referenced_table_name' , ( SELECT '[' + COL_NAME(k.parent_object_id, parent_column_id) + ']'AS [data()] FROM sys.foreign_key_columns (NOLOCK) AS k INNERJOIN sys.foreign_keys (NOLOCK) ON k.constraint_object_id = object_id AND k.constraint_object_id = fkc.constraint_object_id ORDERBY constraint_column_id FOR XML PATH('') ) AS'parent_colums' , ( SELECT '[' + COL_NAME(k.referenced_object_id, referenced_column_id) + ']'AS [data()] FROM sys.foreign_key_columns (NOLOCK) AS k INNERJOIN sys.foreign_keys (NOLOCK) ON k.constraint_object_id = object_id AND k.constraint_object_id = fkc.constraint_object_id ORDERBY constraint_column_id FOR XML PATH('') ) AS'referenced_columns' FROM sys.foreign_key_columns fkc ( NOLOCK ) INNERJOIN sys.objects po ( NOLOCK ) ON fkc.parent_object_id = po.object_id INNERJOIN sys.objects ro ( NOLOCK ) ON fkc.referenced_object_id = ro.object_id WHERE po.type = 'U' AND ro.type = 'U' GROUPBY po.schema_id , ro.schema_id , fkc.parent_object_id , constraint_object_id , referenced_object_id ), /* Index Columns */ IndexColumnsTable AS ( SELECT SCHEMA_NAME(o.schema_id) AS'schema_name' , OBJECT_NAME(o.object_id) AS TableName , ( SELECT CASE key_ordinal WHEN 0 THENNULL ELSE'[' + COL_NAME(k.object_id, column_id) + ']' ENDAS [data()] FROM sys.index_columns (NOLOCK) AS k WHERE k.object_id = i.object_id AND k.index_id = i.index_id ORDERBY key_ordinal , column_id FOR XML PATH('') ) AS cols FROM sys.indexes (NOLOCK) AS i INNERJOIN sys.objects o ( NOLOCK ) ON i.object_id = o.object_id INNERJOIN sys.index_columns ic ( NOLOCK ) ON ic.object_id = i.object_id AND ic.index_id = i.index_id INNERJOIN sys.columns c ( NOLOCK ) ON c.object_id = ic.object_id AND c.column_id = ic.column_id WHERE o.type = 'U' AND i.index_id > 0 GROUPBY o.schema_id , o.object_id , i.object_id , i.name , i.index_id , i.type ), FKWithoutIndexTable AS ( SELECT fk.parent_schema_name AS SchemaName , fk.parent_table_name AS TableName , fk.referenced_schema AS ReferencedSchemaName , fk.referenced_table_name AS ReferencedTableName , fk.constraint_name AS ConstraintName , fk.referenced_columns AS Referenced_Columns , fk.parent_colums AS Parent_Columns FROM FKTable fk WHERE NOTEXISTS ( SELECT 1 FROM IndexColumnsTable ict WHERE fk.parent_schema_name = ict.schema_name AND fk.parent_table_name = ict.TableName AND fk.parent_colums = LEFT(ict.cols, LEN(fk.parent_colums)) ) ) SELECT @@SERVERNAME AS InstanceName , DB_NAME() AS DatabaseName , SchemaName , TableName , Parent_Columns , ReferencedSchemaName , ReferencedTableName , Referenced_Columns , ConstraintName INTO #ForeignKeyWithOutIndex FROM FKWithoutIndexTable ORDERBY DatabaseName , SchemaName , TableName; --输出临时表数据 SELECT * FROM #ForeignKeyWithOutIndex; --生成外键字段缺少的索引,请抽查、检验,确认后批量执行 SELECT 'CREATE INDEX IX_' + LTRIM(RTRIM(TableName)) + '_' + SUBSTRING(Parent_Columns, 2, LEN(Parent_Columns) - 2) + ' ON ' + LTRIM(RTRIM(SchemaName)) + '.' + LTRIM(RTRIM(TableName)) + '(' + Parent_Columns + ');' FROM #ForeignKeyWithOutIndex; --删除临时表 DROPTABLE #ForeignKeyWithOutIndex; 在创建这些索引前最好检查、确认一下,外键字段创建索引能提高性能,但是肯定也要特殊的场景和上下文不适合,所以最好根据实际情况决定。索引创建之后,通过监控工具监控一下数据库性能、等待事件的变化。 参考资料: http://stackoverflow.com/questions/3650690/should-every-sql-server-foreign-key-have-a-matching-index http://sqlblog.com/blogs/greg_low/archive/2008/07/29/indexing-foreign-keys-should-sql-server-do-that-automatically.aspx http://www.sqlskills.com/blogs/kimberly/when-did-sql-server-stop-putting-indexes-on-foreign-key-columns/

优秀的个人博客,低调大师

Spark的这些事&amp;lt;三&amp;gt;——spark常用的Transformations 和Actions

Transformations map,filter spark最长用的两个Transformations:map,filter,下面就来介绍一下这两个。 先看下面这张图: 从上图中可以清洗的看到 map和filter都是做的什么工作,那我们就代码演示一下。 val input = sc.parallelize(List(1,2,3,4)) val result1 = input.map(x=>x*x) val result2 = input.filter(x=>x!=1) print(result1.collect().mkString(",")) print("\n") print(result2.collect().mkString(",")) print("\n") 执行结果如下: 16/08/17 18:48:31 INFO DAGScheduler: ResultStage 0 (collect at Map.scala:17) finished in 0.093 s 16/08/17 18:48:31 INFO DAGScheduler: Job 0 finished: collect at Map.scala:17, took 0.268871 s 1,4,9,16 ........ 16/08/17 18:48:31 INFO DAGScheduler: ResultStage 1 (collect at Map.scala:19) finished in 0.000 s 16/08/17 18:48:31 INFO DAGScheduler: Job 1 finished: collect at Map.scala:19, took 0.018291 s 2,3,4 再回头看下上面那张图,是不是明白什么意思了! flatMap 另外一个常用的就是flatMap,输入一串字符,分割出每个字符 来用代码实践一下: val lines = sc.parallelize(List("hello world","hi")) val words = lines.flatMap (lines=>lines.split(" ")) print(words.first()) print("\n") 执行结果: 16/08/17 19:23:24 INFO DAGScheduler: Job 2 finished: first at Map.scala:24, took 0.016987 s hello 16/08/17 19:23:24 INFO SparkContext: Invoking stop() from shutdown hook 分隔符如果改一下的话: val words = lines.flatMap (lines=>lines.split(",")) 结果会怎样呢? 16/08/17 19:33:14 INFO TaskSchedulerImpl: Removed TaskSet 2.0, whose tasks have all completed, from pool hello world 16/08/17 19:33:14 INFO SparkContext: Invoking stop() from shutdown hook 和想象的一样吧~ distinct,distinct,intersection,subtract 还有几个比较常用的:distinct,distinct,intersection,subtract 来看看代码实践: val rdd1 = sc.parallelize(List("coffee","coffee","panda","monkey","tea")) val rdd2 = sc.parallelize(List("coffee","monkey","kitty")) rdd1.distinct().take(100).foreach(println) 结果: 16/08/17 19:52:29 INFO DAGScheduler: ResultStage 4 (take at Map.scala:30) finished in 0.047 s 16/08/17 19:52:29 INFO TaskSchedulerImpl: Removed TaskSet 4.0, whose tasks have all completed, from pool 16/08/17 19:52:29 INFO DAGScheduler: Job 3 finished: take at Map.scala:30, took 0.152405 s monkey coffee panda tea 16/08/17 19:52:29 INFO SparkContext: Starting job: take at Map.scala:32 代码: rdd1.union(rdd2).take(100).foreach(println) 结果: 6/08/17 19:52:29 INFO DAGScheduler: Job 5 finished: take at Map.scala:32, took 0.011825 s coffee coffee panda monkey tea coffee monkey kitty 16/08/17 19:52:30 INFO SparkContext: Starting job: take at Map.scala:34 16/08/17 19:52:30 INFO DAGScheduler: Registering RDD 11 (intersection at Map.scala:34) 16/08/17 19:52:30 INFO DAGScheduler: Registering RDD 12 (intersection at Map.scala:34) 代码: rdd1.intersection(rdd2).take(100).foreach(println) 结果: 16/08/17 19:52:30 INFO TaskSetManager: Finished task 0.0 in stage 9.0 (TID 9) in 31 ms on localhost (1/1) 16/08/17 19:52:30 INFO TaskSchedulerImpl: Removed TaskSet 9.0, whose tasks have all completed, from pool 16/08/17 19:52:30 INFO DAGScheduler: ResultStage 9 (take at Map.scala:34) finished in 0.031 s 16/08/17 19:52:30 INFO DAGScheduler: Job 6 finished: take at Map.scala:34, took 0.060785 s monkey coffee 16/08/17 19:52:30 INFO SparkContext: Starting job: take at Map.scala:36 代码: rdd1.subtract(rdd2).take(100).foreach(println) 结果: 16/08/17 19:52:30 INFO DAGScheduler: Job 6 finished: take at Map.scala:34, took 0.060785 s monkey coffee 16/08/17 19:52:30 INFO SparkContext: Starting job: take at Map.scala:36 再看看上面的图,很容易理解吧 Actions 常用的Transformations就介绍到这里,下面介绍下常用的Action: reduce,countByValue,takeOrdered,takeSample,aggregate 首先看一下:reduce val rdd5 = sc.parallelize(List(1,2,3,4)) print("reduce action:"+rdd5.reduce((x,y)=>x+y)+"\n") 16/08/18 11:51:16 INFO DAGScheduler: Job 15 finished: reduce at Function.scala:55, took 0.012698 s reduce action:10 16/08/18 11:51:16 INFO SparkContext: Starting job: aggregate at Function.scala:57 countByValue print(rdd1.countByValue() + "\n") 16/08/18 11:51:16 INFO DAGScheduler: Job 11 finished: countByValue at Function.scala:48, took 0.031726 s Map(monkey -> 1, coffee -> 2, panda -> 1, tea -> 1) 16/08/18 11:51:16 INFO SparkContext: Starting job: takeOrdered at Function.scala:50 takeOrdered rdd1.takeOrdered(10).take(100).foreach(println) 16/08/18 11:51:16 INFO DAGScheduler: Job 12 finished: takeOrdered at Function.scala:50, took 0.026160 s coffee coffee monkey panda tea 16/08/18 11:51:16 INFO SparkContext: Starting job: takeSample at Function.scala:52 aggregate 这个要重点介绍一下: Spark文档中aggregate函数定义如下 def aggregate[U](zeroValue: U)(seqOp: (U, T) ⇒ U, combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): U Aggregate the elements of each partition, and then the results for all the partitions, using given combine functions and a neutral “zero value”. This function can return a different result type, U, than the type of this RDD, T. Thus, we need one operation for merging a T into an U and one operation for merging two U’s, as in scala.TraversableOnce. Both of these functions are allowed to modify and return their first argument instead of creating a new U to avoid memory allocation. seqOp操作会聚合各分区中的元素,然后combOp操作把所有分区的聚合结果再次聚合,两个操作的初始值都是zeroValue. seqOp的操作是遍历分区中的所有元素(T),第一个T跟zeroValue做操作,结果再作为与第二个T做操作的zeroValue,直到遍历完整个分区。combOp操作是把各分区聚合的结果,再聚合。aggregate函数返回一个跟RDD不同类型的值。因此,需要一个操作seqOp来把分区中的元素T合并成一个U,另外一个操作combOp把所有U聚合。 val rdd5 = sc.parallelize(List(1,2,3,4)) val rdd6 = rdd5.aggregate((0, 0)) ((x, y) =>(x._1 + y, x._2+1), (x, y) =>(x._1 + y._1, x._2 + y._2)) print ("aggregate action : " + rdd6 + "\n" ) 我们看一下结果: 16/08/18 11:51:16 INFO DAGScheduler: Job 16 finished: aggregate at Function.scala:57, took 0.011686 s aggregate action : (10,4) 16/08/18 11:51:16 INFO SparkContext: Invoking stop() from shutdown hook 我们可以根据以上执行的例子来理解aggregate 用法: 第一步:将rdd5中的元素与初始值遍历进行聚合操作 第二步:将初始值加1进行遍历聚合 第三步:将结果进行聚合 根据本次的RDD 背部实现如下: 第一步:其实是0+1 1+2 3+3 6+4 然后执行:0+1 1+1 2+1 3+1 此时返回(10,4) 本次执行是一个节点,如果在集群中的话,多个节点,会先把数据打到不同的分区上,比如(1,2) (3,4) 得到的结果就会是(3,2) (7,2) 然后进行第二步combine就得到 (10,4) 这样你应该能理解aggregate这个函数了吧 以上就是对常用的Transformations 和Actions介绍,对于初学者来说,动手代码实践各个函数,才是明白其功能最好的方法。 PS :源码 Spark的这些事系列文章: Spark的这些事<一>——Windows下spark开发环境搭建 Spark的这些事<二>——几个概念 Spark的这些事<三>——spark常用的Transformations 和Actions

优秀的个人博客,低调大师

简述负载均衡&amp;CDN技术

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 曾经见到知乎上有人问“为什么像facebook这类的网站需要上千个工程师维护?”,下面的回答多种多样,但总结起来就是:一个高性能的web系统需要从无数个角度去考虑他,大到服务器的布局,小到软件中某个文件的实现,甚至于某个循环内的运算如果出现不严谨都可能导致全盘崩溃。 上面提到web性能优化需要多个角度去考虑,我们无法考虑到所有的优化细节,但可以从我们已知的层面去优化,我们就先从网络层面说起。 ①网络请求路径: 在这个用例中我们可以很清晰的看出网络请求到返回的过程,虽然非常抽象,但足够我们以他为基础来进行优化了。 1)负载均衡 在计算机上负载均衡也类似如此,我们的大BOSS客户端将请求发送至服务器,然而一台服务器是无法承受很高的并发量的,我们就会将请求转发到其他服务器,当然真正的负载均衡架构并不是由一台server转发的另一台server,而在客户端与服务器端中间加入了一个负责分配请求的负载均衡硬件(软件)。 DNS 最早的负载均衡就是利用搭建本地DNS服务器实现的,实现方式简单易懂,为同一个主机名分配多个映射 ,可采用轮循,随机等方式分配请求。 看上去没什么问题,但是在使用过程中会发现,如果其中一个地址down机,我们是无法及时发现的,如果有用户被分配到这个主机就会出现访问失败的状况,同时我们也无法判断每个server的负载,可能会出现,某个server几乎闲置,另外一个server负载压力极高的情况。 硬件设备 负载均衡设备拥有非常好的负载均衡性能,他拥有众多的负载均衡策略(权重,动态比率,最快模式,最小连接数等),可以保证以相对较优的方式分配请求,不过好的东西总是有代价的,那就是价格,一台负载均衡器的售价往往高达十几万甚至几十万,许多企业并不愿意为它买单。 反向代理 第一次听到“反向代理”,可能有些陌生,但如果了解与之对应的正向代理就很好理解了,正向代理通常由客户端主动链接,比如我们的科学的上网方式就是使用正向代理,以达到间接访问网站的目。 而反向代理在服务器端,无需主动链接,当我们访问拥有反向代理的网站时,实际访问的是其反向代理服务器,而非真正的服务器,当请求到达反向代理服务器时,反向代理服务器再将请求转发至服务器。 反向代理是实现负载均衡的主流手段之一,通常使用Nginx等服务器搭建,Nginx同样拥有众多的分配策略,以保证平均分配压力。 2)CDN 视频总在缓冲,图片各种加载不出来,几年前是再正常不过的事了,在当时大家也没觉得是回事,但把这种情况放在现在,我想人们绝对直接就小红叉了吧,那么我们如何避免这样的情况呢?这就是我要说的,内容分发网络(Content Delivery Network),简称:CDN。CDN简单的来说就是存储一些静态文件的一台或多台服务器,通过复制,缓存等方式,将文件保存其中。 1.哪些是静态文件? css,html,图片,媒体都属于静态文件,也就是说用户发送的请求不会影响静态文件的内容,而jsp,php等文件就不属于静态文件,因为他们的内容会因我们的请求而发生改变。 2.CDN如何实现加速? 通常情况下,我们所要的数据都是从主服务器中获取,但假如我们的主服务器在南方,而访问用户在北方,那么访问速度就会相对变慢,变慢的原因有很多,例如传输距离,运营商,带宽等等因素,而使用CDN技术的话,我们会将CDN节点分布在各地,当用户发送请求到达服务器时,服务器会根据用户的区域信息,为用户分配最近的CDN服务器。 3.CDN数据从哪里来? 复制,缓存,CDN服务器可以在用户请求后缓存文件,也可以主动抓取主服务器内容。分布在各地的CDNS: 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/zhibo 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-04-20本文作者:吴纹羽本文来自:“互联网架构师 微信公众号”,了解相关信息可以关注“互联网架构师”

优秀的个人博客,低调大师

Chromium Viz 浅析 - SkiaRenderer &amp; SkiaOutputSurface

关于 Viz 的系列文章 Chromium Viz 浅析 - 介绍篇Chromium Viz 浅析 - 合成器架构篇 Chromium 关于光栅化和合成的一些主要性能优化项目包括 OOPD (Out of Process Display Compositor,进程外 Display 合成器), OOPR (Out of Process Rasterization,进程外光栅化) 和 SkiaRenderer。 我们在Chromium Viz 浅析 - 合成器架构篇介绍过 OOPD,它的主要目的是将 Display Compositor 从 Browser 进程迁移到 Viz 进程(也就是原来的 GPU 进程),Browser 则变成了 Viz 的一个 Client,Renderer 跟 Viz 建立链接(CompositorFrameS

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册