Microsoft SQL Server 2016最近在关系数据库管理系统(RDBMS)中处于领先地位。 高性能,安全性,分析和云兼容性的结合使其成为领先的RDBMS 。 SQL Server 2017甚至支持R和Python编程语言,这进一步提高了它在学术机构中的数据科学家和数据专业人员中的吸引力。

这是一个激动人心的时刻的原因有很多是外本文的范围,SQL Server开发,但要简明概括他们:SQL Server已不仅成为头号RDBMS,这也成为一个 RDBMS。

牢记这些令人印象深刻的SQL Server新版本,您可能会想知道如何从预期对整体生产力产生最大影响的功能中获得最大价值,尤其是在您缺乏经验的情况下。 另一方面,如果您不参加每个网络研讨会,也不在浏览每篇有关新功能的文章,那么不必担心太多。 许多公司仍在使用SQL Server 2008 R2,尤其是在金融和医疗保健等受到严格监管的行业中。

我会警告任何人,在不首先精通(如果不精通)基本技能之前,不要专注于SQL Server的任何新功能。

本文解释了为什么元数据很有价值,什么是元数据,然后介绍了使用引用元数据的Transact-SQL(T-SQL)代码解决的两个实际问题。 从查询目录视图到动态使用元数据,您应该不了解将减少您熟悉数据和独立解决问题的时间和精力,从而使您的SQL Server开发技能更有价值的知识。

无论您使用的是哪个行业,公司或什至当前版本的SQL Server,您都可以学习这三个通用技能,这些技能可以高度移植,甚至可以跨越相对较大的软件版本跳跃(例如,从SQL Server 2008 R2到2014)。 。

开发人员的三项基本SQL Server技能

SQL是您必须具备的首要技能,也是最显而易见的技能。学习这种脚本语言的主要原因之一(除了它很有趣之外)还在于它的可传递性,即使在其他RDBMS之间也是如此。 当然,我说的是美国国家标准协会(ANSI)的标准SQL(SQL)语法,不一定是T-SQL,这是Microsoft的SQL方言。 就个人而言,我还发现学习SQL / T-SQL语法的新元素比适应图形用户界面上的新功能要容易。 出于本文的目的,我将基于以下假设来研究T-SQL:假定阅读本文的人都是SQL Server开发人员的某种变体。

PowerShell是第二项技能。 PowerShell是另一种脚本语言,允许用户自动执行各种有用的任务,这些任务通常涉及运行SQL Server Reporting Services报表,安排作业以及基本上完成许多数据库管理员(DBA)的工作。 但是,使PowerShell更具吸引力的是它替代了使用.NET对象和方法的Windows DOS批处理语言(即,在命令提示符下使用的批处理语言)。 其价值的另一个原因是,与T-SQL不同,PowerShell可以自动化跨越Windows和SQL Server环境的任务。

除了这两种丰富的脚本语言之外,还有第三种技能可以使任何精通SQL Server的用户受益,这就是元数据的使用。 从技术上讲,理解SQL Server元数据(就本文而言,除非明确指定,否则对“元数据”的所有引用都将意味着“ SQL Server”)是学习的主题,也是锻炼和应用技能(即记忆关系和学习的机会) T-SQL)-本身并不是一项技能。 因此,每当我提到“元数据的使用”时,我的意思是“开发人员在T-SQL中应用元数据知识的程度。”

但是,我认为,元数据也是开发人员社区中最被忽视和低估的主题之一(而学习T-SQL显然不是)。 许多入门的SQL Server或T-SQL书籍甚至都不会在以后的章节中讨论它,即使有的话,甚至甚至很少。

熟悉SQL Server元数据是一项比大多数讲师似乎更有价值的技能,特别是对于初学者而言,因为这是在SQL语言,数据库设计以及物理和逻辑处理中将知识应用于理论概念的一种实用方法。

即使对于经验丰富的开发人员和DBA,SQL Server元数据也可能非常有价值,因为它的实用性会随着您在数据库设计和编程的其他领域的创造力和能力而扩展。 在整篇文章中,我将提供一些T-SQL脚本的示例,这些示例会增加复杂性,并演示如何在尝试解决问题时熟悉元数据会变得无价。

但是,在深入研究示例之前,我应该提出几个重要的一般性观点。 微软的网站,通常称为“在线图书”(BOL),是我可以推荐的关于此主题的唯一最大资源。 实际上,您应该查看此页面以熟悉各种类型的元数据,以及此页面上的有关如何访问元数据(即使用目录视图)的信息。

基本元数据查询

查询对象目录视图的简单性和灵活性使即使是对SQL知识最少的用户也可以很好地浏览数据库中的对象和关系。 请允许我通过一个简单的示例演示为什么元数据对开发人员有用。

对于那些感兴趣的人,请注意,我正在使用SQL Server 2016 Express Edition和AdventureWorks2014示例数据库(两者都是完全免费的)。

假设您是虚构公司Adventure Works Cycles的新员工。 在查看了几张表后,您会发现名为“ BusinessEntityId”的列出现了很多。 让查询在数据库中显示具有该名称的每一列不是很好吗? 了解有关SQL Server元数据的基础知识使之变得容易。

由于您知道[sys]。[all_objects],[sys]。[schemas]和[sys]。[all_columns],因此可以编写一个简单的查询来实现BusinessEntityId的单个视图。

use AdventureWorks2014
go
select s.name as 'SchemaName',o.name as 'TableName',c.name as 'ColumnName'
from sys.schemas as sinner join sys.all_objects as oon s.schema_id = o.schema_idinner join sys.all_columns as con c.object_id = o.object_id
where c.name like 'BusinessEntityId'
and o.type = 'U'
order by SchemaName,TableName,ColumnName;

这是结果集:

元数据不仅仅用于编写基本的临时查询。 考虑进行难以置信的复杂查询的机会,以回答极其困难或耗时的问题。 例如,给定数据库中存在多少个重复索引? 它们是什么类型的索引?

不管您当前的T-SQL技能水平如何,尤其是通过目录视图和动态管理视图(DMV)熟悉元数据都非常有价值。 这是一种有趣且易于访问的机制,可以磨练您对T-SQL语言和公司主数据的了解,并随着您在数据库编程中不断增强的能力而扩展。

现在,按照其余查询中的注释进行说明,这些注释说明了使用元数据(结合一些业务知识)探索主数据如何可以帮助您独立回答问题。

use AdventureWorks2014
goselect s.name as 'SchemaName',o.name as 'TableName',c.name as 'ColumnName'
from sys.schemas as sinner join sys.all_objects as oon s.schema_id = o.schema_idinner join sys.all_columns as con c.object_id = o.object_id
where c.name like 'BusinessEntityId'
and o.type = 'U'
order by SchemaName,TableName,ColumnName;--Now join two tables using BusinessEntityId
select *
from HumanResources.Employee as einner join Person.Person as pon e.BusinessEntityID = p.BusinessEntityID
order by p.BusinessEntityID;--hmm, it looks like PersonType "EM" stands for "Employee," but what does "SP" mean?
--let's see if there are any other PersonType values
select distinct PersonType
from HumanResources.Employee as einner join Person.Person as pon e.BusinessEntityID = p.BusinessEntityID
order by p.BusinessEntityID;--apparently, there are none
--run the previous query again and look for patterns
--perhaps it has something to do with JobTitle?
select distinct p.PersonType,e.JobTitle
from HumanResources.Employee as einner join Person.Person as pon e.BusinessEntityID = p.BusinessEntityID
order by p.BusinessEntityID;--looks like it could have something to do with all sales-related jobs

如果您了解有关SQL Server元数据的方法,则可以了解很多关于公司数据的信息。

元数据的高级应用

但是元数据的更高级应用又如何呢? 如果您是在公司工作多年的经验丰富的开发人员,该怎么办? 为什么要学习SQL Server元数据? 好吧,一个更复杂的例子可能会让您信服。

在Grant Fritchey在PASS本地用户组活动中的演讲之一中,他描述了有关如何提高SQL Server性能的10条技巧。 其中之一是寻找嵌套视图并重写它们(理想情况下是通过连接到表)。 所谓“嵌套”,是指创建视图时引用其定义中的其他视图。 给定视图定义中嵌套的级别越多,性能下降的幅度越大。

显而易见的解决方案是不编写嵌套视图,但这也不是避免其假设存在的借口,因为这样做会限制性能调整的熟练程度,并依赖于将来不会成为问题的假设。 而且,如果您正在调查数据库性能问题并且不确定嵌套视图是否困扰数据库,那么值得您花时间至少看看一下此问题是否是必须解决的问题。 。

但是,您如何去做呢? 除了手动右键单击对象资源管理器中的每个视图并查看定义之外,为什么不创建一个利用动态SQL为您提供答案的元数据存储过程?

我写了两个存储过程,它们将在本文后面引用,以帮助您开始解决此问题。 碰巧有一个名为“ sys.dm_sql_referenced_entities”的系统函数,它接受两个输入参数:合格的视图名称(即“ schema.view”或“ [schema]。[view]”)和一个“引用类”。

就本文而言,只知道我们仅对数据库对象感兴趣,这意味着我们需要在第二个参数中使用字符串“ object”。 如果您想知道,如果使用其他引用类,则可以查看触发器的引用。 有关更多信息,请参见此链接 。

既然我已经提到了“动态sql”,那么我应该解决两类可能涉及的问题:安全性和性能。

动态SQL成本:安全性和性能

动态SQL本质上是“编写SQL的SQL”。 尽管它在存储过程中非常有用,但会带来一些成本。 但是,在详细说明这些成本之前,我必须指出,与嵌套视图可能对数据库产生的长期影响相比,它们可以忽略不计。

我很清楚,SQL注入是一种严重的安全风险,当开发人员编写动态SQL时,这种风险就有可能发生。 对我来说幸运的是,“父”存储过程不接受用户输入,也不打算在任何面向客户的应用程序中使用。 更具体地说,动态SQL不会接受来自应用程序前端的用户输入来获取其参数的值。

另一方面,如果您关心的是动态SQL的性能,那么我为您提供两个答复:

首先,此“嵌套视图”练习的目的是通过解决潜在的严重问题来提高数据库的整体性能,而这种问题很少发生(也就是说,除非您有一群开发人员继续定期嵌套视图,在这种情况下,您会遇到更大的问题)。

由于问题(理论上)很少发生,因此您应该只希望不频繁运行代码,这意味着代码性能不佳只会在您多次运行时才会引起关注。 换句话说,如果您专注于这些过程的性能却以牺牲整个数据库的性能为代价,则将完全失去问题的背景,因此,不要对代码的性能考虑得太严格(但是如果可以,请随时进行更多调整)。

其次,您可能还担心由于动态SQL的非关系​​性质,性能会受到影响。 我完全同意这样一种观点,即任何编写SQL的人都应在可能的情况下尽力做到相关性(即,以符合集合论原理的方式进行编写)。 不幸的是,没有比该方法更符合关系模型的解决该问题的替代方法了。 如果您不同意,或者找到任何使我的代码更具关系性的方法来改进我的代码,请立即与我联系。 我还应该提到,我已经写了整篇文章 。

为了快速总结这些批评:与嵌套视图可能对不断增长的数据库产生的长期和累积的,性能下降的影响相比,安全风险和性能问题可忽略不计。 该代码本身可能并未针对可伸缩性和性能进行优化,但是如果使用得当,它将有助于您确保数据库处于最佳状态。

使您的元数据动态化

那么,动态SQL是否值得承担这些风险? 我能给您的最佳答案是,这取决于您要解决的问题的价值。 动态SQL是SQL开发人员工具带中的另一种工具,它大大增加了解决问题的方式。 自动执行此嵌套视图清除程序搜寻的第一步是使用sys.dm_sql_referenced_entities(为简洁起见,我将使用“被引用实体”)编写动态SQL语句,以返回所有被引用视图的名称和引用频率:

[dbo]。[CountObjectReferences]

use [AdventureWorks2014]
gocreate procedure [dbo].[CountObjectReferences] (@QualifiedView as varchar(255),@RefCount as int output
) as
/*******************************************************************************************************************
Author: Alex Fleming
Create Date: 11-05-2017
This stored procedure accepts a string that contains a qualified view or table and returns the number of references.
Examples of valid parameters: 'Sales.vStoreWithContacts' or '[Sales].[vStoreWithContacts]'
*******************************************************************************************************************/
set nocount on;
begindeclare @DynamicSQL varchar(3000) = ('select count(*)from sys.dm_sql_referenced_entities(' + '''' + @QualifiedView + '''' + ',''object'') as RefEntinner join sys.all_views as AllViewson RefEnt.referenced_id = AllViews.object_idwhere RefEnt.referenced_class = 1and RefEnt.referenced_minor_name is null;');exec (@DynamicSQL);end;/********************************Test*********************************************
Note: AdventureWorks2014 does not contain any nested views out-of-the-box.
Consequently, I have created several for testing.  Here's the definition
of two (one of them is nested by two levels):create view [HumanResources].[DuplicateEmployeeView] as
(
select *
from HumanResources.vEmployee       ------standard view in AdventureWorks2014------
);create view [HumanResources].[DuplicateEmployeeView3] as
(
select *
from HumanResources.DuplicateEmployeeView
);declare @RefCount int;
exec dbo.CountObjectReferences @QualifiedView = 'HumanResources.DuplicateEmployeeView3', @RefCount = @RefCount output;
*********************************************************************************/

[dbo]。[FindNestedViews_v3]

use AdventureWorks2014gocreate procedure dbo.FindNestedViews_v3 (@ViewRefCount as int output) as/*******************************************************************************************************************Author: Alex FlemingCreate Date: 11-05-2017This stored procedure finds all of the views in the current database, stores them in a temp table, then passes them as parameters into the dbo.GetViewReferences stored procedure and stores the results in a new temp table, which isthen queried for all views containing one or more views in their definitions.*******************************************************************************************************************/set nocount on;beginif object_id ('[tempdb]..[#SchemaViewTemp]') is not nulldrop table #SchemaViewTemp;create table #SchemaViewTemp(  SVID int identity(1,1) NOT NULL primary key,SchemaViewString varchar(2000) NULL,RefCount int null);  insert into #SchemaViewTemp (SchemaViewString)select s.name + '.' + v.name as 'SchemaViewString'from sys.all_views as vinner join sys.schemas as son v.schema_id = s.schema_idwhere v.object_id > 0order by SchemaViewString;if object_id ('[tempdb]..[#ViewReferences]') is not nulldrop table #ViewReferences;--this table stores the output of the insert/exec statement--(can't use the same table because there is no way of updating based on an exec statement)create table #ViewReferences(  RefID int identity(1,1) not null primary key,RefCount int null);  declare @UpdateStmt varchar(500);declare @cnt as int = 0;declare @ViewString as nvarchar(255);declare NestedViewReader cursor forselect SchemaViewStringfrom #SchemaViewTemp;open NestedViewReader;fetch next from NestedViewReaderinto @ViewStringwhile @@FETCH_STATUS = 0begininsert into #ViewReferences (RefCount)exec @ViewRefCount = dbo.CountObjectReferences@QualifiedView = @ViewString, @RefCount = @ViewRefCount output;set @UpdateStmt = ('update #SchemaViewTemp set RefCount = ' + cast((select RefCount from #ViewReferences where RefID = @cnt + 1) as varchar(3)) +' where SVID = 1 + ' + cast(@cnt as varchar(2)) + ';');print @UpdateStmt;--for troubleshootingexec (@UpdateStmt);set @cnt = @cnt + 1;fetch next from NestedViewReaderinto @ViewStringendclose NestedViewReader;deallocate NestedViewReader;drop table #ViewReferences;select *from #SchemaViewTemp where RefCount > 0order by RefCount desc;end;go/********************************Test***********************************declare @ViewRefCount as int;exec dbo.FindNestedViews_v3 @ViewRefCount = @ViewRefCount output;************************************************************************/

在动态SQL和游标之间,T-SQL的某些功能只是该解决方案不可避免的部分。 据我所知,使该想法起作用的唯一方法是使用动态SQL执行引用的实体系统功能。

此外,多次运行动态SQL的唯一方法是使用游标(除非您想尝试使用扩展的存储过程,但这不在本文的讨论范围之内)。 除了动态SQL和游标之外,您还有一些重要的设计决策。

一旦您有一个执行在数据库,模式和视图名称中传递的动态SQL语句的存储过程,您可能希望放慢速度并考虑设计,特别是通过回答设计问题:“我是否要中断?将此存储到另一个存储过程中并调用它,还是将所有逻辑封装在一个巨型存储过程中?”

我将动态SQL包含在一个单独的存储过程中,而不是将其作为一个庞大的存储过程的第一部分,这一事实是我的故意设计决定。 当时,我认为阅读和维护起来会更容易。 此外,我想确保动态SQL的执行计划是一致的(存储过程的优点之一是防止优化器偶尔生成不同的执行计划)。 我还发现编写和测试更加容易。

确定如何存储合格的视图,将它们传递给[dbo]。[CountObjectReferences]存储过程,存储游标的结果,然后显示最终输出,这是此问题中比较困难的部分之一。 我们可以使用表变量,临时表,用户定义的表或视图。

如果您在此存储过程中使用嵌套视图,那将有多讽刺? 从技术上讲,只有当您在其中编写存储过程的数据库中没有除过程中的嵌套视图之外的嵌套视图,这才具有讽刺意味。 现在很讽刺!

我之所以选择临时表,是因为我对表变量不太熟悉。 我不想在此过程中维护用户定义的表,也没有安全方面的顾虑阻止我直接访问数据(因此排除了视图)。 稍后添加索引以及轻松地在本地和全局之间更改临时表的范围的能力也是吸引我的最初决定的吸引人的特征。

从一开始我就没有澄清过我是否想要一个更详细的结果集(它为用户提供尽可能多的相关元数据)还是包含最少的数据量以换取更高的性能,可维护性和简便性。

在考虑了原始问题并认为我希望能够临时运行这些存储过程之后,后者成为我的偏爱。我只需要一个简单的结果集即可找到嵌套视图。 基本上,您希望返回尽可能少的信息来回答您的问题。 在我们的例子中,这意味着返回所有包含其他视图的视图名称,理想情况下,返回原始视图和表之间存在多少级嵌套视图。

在继续之前,我必须指出,我知道使用游标会限制这种方法的可扩展性。 另一方面,在数据库中嵌套视图也不是完全可扩展的数据库设计方法,因此也请记住这一点。

如果我不了解[sys]。[views]或引用的实体功能,这些存储过程将是不可能的。 实际上,我最初是在[sys]。[schemas]和[sys]。[all_columns]上加入了[sys]。[all_objects],它们的性能比本文引用的版本差。 指出元数据特权和动态SQL背后的安全性问题也很重要。

由于安全策略根据组织的规模和行业的不同而不同,因此,每当从事涉及SQL Server开发的工作时,都应使用这些因素使您的期望与要使用的DBA保持一致。 有关SQL Server元数据安全性的更多信息,请参阅Kalen Delaney的本文 。 实际上,我还建议您从Delaney中阅读有关SQL Server元数据的更多信息。

其次,元数据访问需要您的DBA的批准。 虽然允许任何用户访问系统元数据都存在很小的安全风险,但这实际上取决于您的DBA或公司对开发人员的信任程度。 除非您在受到严格监管的行业工作,否则这对您来说不太可能成为问题。

当使用术语元数据时,我特别专注于系统元数据。 我还应该指出DMV的用处,因为它们在DBA中得到了广泛的使用和依赖,并建议任何开发人员都应该熟悉上述所有信息。

我发现最具挑战性的是快速找到正确的DMV或系统元数据-当我从上一段中得出自己的建议时,这个问题肯定会减少。 关于这一点,我鼓励遇到相同问题的任何人使用我的第一个示例,然后根据您要查找的内容对其进行修改(即,对其进行修改以根据关键字搜索来查找感兴趣的DMV或系统视图)。

通过额外的实践,在没有第三方软件任何帮助的情况下,通过最大限度地提高您在SQL Server中解决问题的能力,元数据和DMV对您来说将变得无比宝贵。 更好的是,您大部分依赖SQL Server元数据的代码仍将在Microsoft Azure中运行,从而使元数据的应用成为一种更具可移植性的技能。

考虑到技术兴衰的混乱,可转让技能越来越难以识别和依赖,这使开发人员的生活(有时)变得不必要地困难。 因此,SQL Server元数据的价值证明了Microsoft对用户授权的奉献精神,这无疑表明了他们与开发人员一起为您创建产品的迹象。

翻译自: https://www.javacodegeeks.com/2018/02/microsoft-sql-server-metadata-developers.html

针对开发人员的Microsoft SQL Server元数据相关推荐

  1. 访问 Microsoft SQL Server 元数据的三种

    上海微创软件有限公司 肖桂东 适用读者:Microsoft SQL Server 中.高级用户 元数据简介 元数据 (metadata) 最常见的定义为"有关数据的结构数据",或者 ...

  2. SQL Server 中WITH (NOLOCK)浅析 2014-08-30 11:58 by 潇湘隐者, 58264 阅读, 33 评论, 收藏, 编辑 概念介绍 开发人员喜欢在SQL脚本

    SQL Server 中WITH (NOLOCK)浅析 概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同 ...

  3. [MS]Microsoft SQL Server 2008 R2 开发版/企业版/标准版

    Microsoft® SQL Server® 2008 R2 是一个功能强大且可靠的数据管理系统,它功能丰富,能保护数据,并且可改善嵌入式应用程序.轻型网站和应用程序以及本地数据存储区的性能. 数据中 ...

  4. 《Microsoft Sql server 2008 Internal》读书笔记--第八章The Query Optimizer(1)

    <Microsoft Sql server 2008 Interna>读书笔记订阅地址: http://www.cnblogs.com/downmoon/category/230397.h ...

  5. 《Microsoft Sql server 2008 Internals》读书笔记--第九章Plan Caching and Recompilation(10)

    <Microsoft Sql server 2008 Internals>读书笔记订阅地址: http://www.cnblogs.com/downmoon/category/230397 ...

  6. Microsoft SQL Server 2000 中的数据转换服务 (DTS)

    摘自:http://www.microsoft.com/china/MSDN/library/data/sqlserver/DataTransformationServices(DTS)inMicro ...

  7. Microsoft SQL Server 2000整合规划

    Microsoft SQL Server 2000整合规划 更新日期: 2004年06月24日 SQL Server技术文章 作者:Allan Hirt 投稿人:Tom Davidson和Shaun ...

  8. Microsoft SQL Server 2012(附序列号)

    Microsoft SQL Server 2012是微软发布的新一代数据平台产品.SQL Server 2012不仅延续现有数据平台的强大能力,全面支持云技术与平台,并且能够快速构建相应的解决方案实现 ...

  9. 把Oracle数据库移植到Microsoft SQL Server 7 0

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 把Ora ...

最新文章

  1. java服务限流_SpringCloud微服务:Sentinel哨兵组件,管理服务限流和降级
  2. java中hashcode作用_Java中hashCode的作用
  3. video和dvd audio区别:
  4. 什么是互联网大厂_2020阿里、腾讯、字节跳动等14家互联网大厂薪资水平大汇总...
  5. 手机这5个反人类的设计,你能容忍到第几个?
  6. 计算机网络---IP数据报组成计及IP模块工作流程
  7. C++学习008-delete与delete[]的差别
  8. duplicate symbols for architecture arm64的问题结决方法
  9. python中heading_python如何抓取几个csv的heading并存在excel里?
  10. ESXi主机从6.7升级到ESXi 7.0.3后无法识别Emulex LPe12000 HBA卡
  11. 数字证书和SSL的学习
  12. 基于微信视频点播小程序系统设计与实现 开题报告
  13. OJ常用术语解释。AC、WA、TLE、CE、RE、MLE、PE等状态术语的解释
  14. 面向金融机构的阿里云SDWAN解决方案解读
  15. BAT程序员工作的真实情况
  16. Mac锁屏 设置快捷键
  17. KONG 之 rate-limiting
  18. 网站地图(sitemap)如何优雅生成?
  19. 泰克TDS1000B示波器使用说明
  20. 文献阅读 - Combining Sketch and Tone for Pencil Drawing Production

热门文章

  1. mybatis多个参数(不使用@param注解情况下),sql参数占位符正确写法
  2. 一篇文章了解RPC框架原理
  3. JAVA面试常考系列十一
  4. @Controller,@Service,@Repository,@Component详解
  5. Hadoop入门(二)集群安装
  6. ssh(Spring+Spring mvc+hibernate)——Emp.hbm.xml
  7. 使用ueditor实现多图片上传案例——Service层(IShoppingService)
  8. 把Springboot项目部署到服务器上和结束运行
  9. java 单一职责原则_设计模式之单一职责原则
  10. matlab盒子分形维数_分形:盒子维数