首页 文章 精选 留言 我的

精选列表

搜索[小程序·云开发],共10036篇文章
优秀的个人博客,低调大师

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/

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

DLNA&amp;UPnP开发笔记(2)

1. UPnP协议组成 UPnP协议中,定义了两个主要的组件,一个是设备(Device),一个是控制点(Control Point)。这就是为什么很多UPnP协议栈的SDK的接口代码一般都主要由Device和Control Point构成。设备是在网络中可见的对象,而控制点在网络中不可见。 一个UPnP的设备(Device)是不能直接访问和控制另一个UPnP的设备(Device)的,对设备的访问和控制都必须通过控制点(Control Point)来代为完成。而控制点对设备的控制则主要是由设备定义的“服务”(Service)来实现。 设备(Device)需要向网络中广播自己的信息,并提供设备描述和服务(Service)描述,并发送设备事件消息. 控制点(Control Point)则是搜索设备,并使用其提供的服务(Service)访问和控制设备,同时监听设备事件消息。 2. 典型的UPnP AV应用架构 如图所示是一种典型的UPnP AV应用架构,它来自《UPnP-av-AVArchitecture》。在一个典型的UPnP应用中,有三个主体,一个服务器(MediaServer),一个播放器(MediaRender),以及一个控制点(Control Point)。 服务器(MediaServer)主要负责提供多媒体文件的浏览和控制。 播放器(MediaRender)主要负责提供播放和渲染。 控制点(Control Point)则控制整个播放过程。 它们三个在物理上可以是同一个设备,当然,也可以在不同的设备上。 对应到UPnP协议组件的话,“MediaServer”和“MediaRnederer”都属于UPnP的Device。 “ContentDirectory”、“ConnectionManager”、“AVTransport”、“RenderingControl”这些都属于UPnP设备所提供的服务(Service),通过这些服务描述,Control Point就知道该如何访问和控制设备了。 3. UPnP的设备描述和服务描述 UPnP的设备(Device)是通过广播包来通知局域网中的控制点自己的设备信息和服务的,而这些设备信息和服务都必须根据UPnP协议规定的XML文档格式来编写,UPnP提供了标准的模板可以参考,具体的文档地址: http://upnp.org/sdcps-and-certification/standards/sdcps/ 由这些文档我们可以看到,UPnP官网为我们定义了12种设备,在每种设备的文档中详细地定义了设备描述XML如何编写,定义了每种设备需要实现哪些服务,每种服务的XML文档如何编写。 到这里,我们其实可以看到,实现一个上述的UPnP AV应用也并没有那么可怕,一切都是有章可循的,我们需要做的就是熟读协议所定义了一系列文档。 本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1637727,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

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

用户登录
用户注册