msdb 数据库

介绍 (Introduction)

Nowadays, most mid-size companies have implemented a Data Warehouse (DWH) solution. This DWH can be designed using a set of tools (or features) from Microsoft SQL Server. One of them is SQL Server Integration Services, also known as SSIS.

如今,大多数中型公司已实施了数据仓库(DWH)解决方案。 可以使用Microsoft SQL Server中的一组工具(或功能)来设计此DWH。 其中之一是SQL Server Integration Services,也称为SSIS。

Basically, this feature (SSIS) allows us to extract, transform and load data from almost any kind of source to almost any kind of destination : flat file, Excel File, RDBMS. Based on our version of SQL Server, we will use either Visual Studio (starting SQL Server 2012) or SQL Server BI Development Studio (before SQL Server 2012).

基本上,此功能(SSIS)使我们能够将数据从几乎任何类型的源中提取,转换和加载到几乎任何类型的目标中:平面文件,Excel文件,RDBMS。 基于我们SQL Server版本,我们将使用Visual Studio(从SQL Server 2012开始)或SQL Server BI Development Studio(在SQL Server 2012之前)。

Microsoft defines SSIS as a plaftform for building enterprise-level data integration and transformation solutions. We can easily imagine that building a data warehouse is not the only application SSIS is designed for. There is an article on Technet listing ten typical usages of SSIS : Typical Uses of Integration Services.

Microsoft将SSIS定义为构建企业级数据集成和转换解决方案的平台 。 我们可以很容易地想象到,构建数据仓库并不是SSIS设计的唯一应用程序。 Technet上有一篇文章,列出了SSIS的十种典型用法: Integration Services的典型用法。

With some basic searching, you will find in Microsoft’s documentation, articles and blog posts that there are two kinds of deliverables when we work with SQL Server Integration Services : we can build and deploy SSIS deliverables either as packages or projects.

通过一些基本的搜索,您可以在Microsoft的文档,文章和博客文章中找到与SQL Server Integration Services一起使用时可交付的两种类型:我们可以将SSIS交付或打包或部署为项目

There are plenty of differences between those two modes :

这两种模式之间有很多差异:

  • You cannot deploy projects prior to SQL Server 2012 : project deployment appeared with this version. This mode of deployment overcomes package deployment, which is now referred to « legacy deployment mode ».

    您无法在SQL Server 2012之前部署项目:此版本中出现了项目部署。 这种部署模式克服了程序包部署,现在称为“旧版部署模式”。

    So, before SQL Server 2012, only package deployment is available. Microsoft provides tools to migrate from an older version of a SSIS packages to a SSIS project containing this package.

    因此,在SQL Server 2012之前,仅程序包部署可用。 Microsoft提供了从旧版本的SSIS软件包迁移到包含该软件包的SSIS项目的工具。

  • A package can be compared to executable code or a workflow description. A project contains a set of packages and has advanced functionalities compared to a simple package. For instance, you can define a connection to a SQL Server instance or an Excel file at project-level. This connection will be accessible to all packages defined in the project. In legacy mode, you will need to create the exact same connection in each package you would group into a single project.

    可以将包与可执行代码或工作流描述进行比较。 与简单的程序包相比,一个项目包含一组程序包,并且具有高级功能。 例如,您可以在项目级别定义到SQL Server实例或Excel文件的连接。 项目中定义的所有软件包都可以访问此连接。 在传统模式下,您需要在要分组到一个项目中的每个包中创建完全相同的连接。

  • Packages and projects are not stored the same way. The former is stored either in msdb database or on filesystem while the latter is stored in a SQL Server database called the SSIS Catalog.

    包和项目的存储方式不同。 前者存储在msdb数据库或文件系统中,而后者存储在称为SSIS目录SQL Server数据库中。

  • Etc.

    等等。

You can find a comparison on MSDN : Deploy Integration Services (SSIS) Projects and Packages.

您可以在MSDN上找到一个比较: 部署集成服务(SSIS)项目和包 。

No matter these differences, in both modes, you can run packages using (scheduled) SQL Server Agent Jobs.

无论这些差异如何,在两种模式下,都可以使用(预定的)SQL Server代理作业运行程序包。

But this article is not about SSIS development or deployment. There are plethora of tutorials and courses on the subject available on the web. In fact, this article will focus on the extraction of information about SSIS Packages (not projects) deployed in MSDB database (not on file system), using a set of T-SQL queries. The results of those queries could be stored in tables inside a database.

但是本文与SSIS开发或部署无关。 网络上有大量关于该主题的教程和课程。 实际上,本文将重点介绍使用一组T-SQL查询提取有关部署 在MSDB数据库 (而非文件系统)中的SSIS包 (非项目) 信息。 这些查询的结果可以存储在数据库内部的表中。

This extraction process was designed to be the input of an analysis process in order to prepare a side-by-side migration and pinpoint problematic aspects before going any further. The objective was to plan preventive corrections a long time before the actual migration process, when it’s possible. This analysis process will eventually be the subject of another article. I think the entire process (extraction plus analysis) can also be used to ensure quality of development, or simply to document existing packages.

此提取过程被设计为分析过程的输入,以便在进行下一步操作之前准备并排迁移并查明有问题的方面。 目的是在实际迁移过程之前很长时间计划预防性纠正措施。 该分析过程最终将成为另一篇文章的主题。 我认为整个过程(提取和分析)也可以用于确保开发质量,或仅用于记录现有软件包。

Now, let’s dive into SSIS fundamentals. We will view (or review) how a SSIS package is defined and designed. This will allow us to pinpoint relievant components or properties that would be useful to extract, just as a list or for further analysis.

现在,让我们深入研究SSIS的基础知识。 我们将查看(或审查)如何定义和设计SSIS包。 这将使我们能够精确地确定卸压成分或特性,这些成分或特性将对提取有用,如清单或进一步分析。

SSIS包:我们需要知道的。 (SSIS Packages : what we need to know.)

In the following sections, we will sometimes use screen captures of a SSIS package in SQL Server BI Development Studio. The package used is called “Lookup Sample” and taken from SQL Server Integration Services Product Samples. We will refer to this package as our demo package or example package.

在以下各节中,有时我们将使用SQL Server BI Development Studio中的SSIS包的屏幕截图。 所使用的软件包称为“查找样本”,取自SQL Server Integration Services产品样本 。 我们将此包称为演示包或示例包。

SSIS Package composition and properties (overview)

SSIS包的组成和属性(概述)

Flows

流量

First of all, when we open either a new or an existing SSIS package in SQL Server Business Intelligence Development Studio or Visual Studio, we will notice that it’s composed in two kinds of « flows » :

首先,当我们在SQL Server商业智能开发Studio或Visual Studio中打开一个新的或现有的SSIS包时,我们会注意到它由两种“流”组成:

  • The control flow : a workflow which lists tasks to perform during package execution. Tasks can be grouped in containers. In this case, containers are seen as undividable tasks.

    控制流 :列出要在包执行期间执行的任务的工作流。 任务可以分组在容器中。 在这种情况下,容器被视为不可分割的任务。

  • The data flow : a data flow exists for most tasks on data in the control flow. It’s the way data is treated. Some tasks can be defined without data flow. Particularly, database connections are used there (as Data Source or Data Destination)

    数据流 :对于控制流中的数据,大多数任务都有一个数据流。 这就是处理数据的方式。 可以在没有数据流的情况下定义某些任务。 特别是,在那里使用数据库连接(作为数据源或数据目标)

Here is a diagram from Microsoft that summarize the explanation from above:

这是Microsoft的图表,总结了上面的说明:

You will find below a screen capture with an example control task and its corresponding data flow view.

您将在下面的屏幕截图中找到一个示例控制任务及其相应的数据流视图。

Connections

连接数

In data flow, we generally take data from a source (the extract), we eventually process these data (transform) and store it to a destination (load). Source and destination are defined by connections. There are various kinds of connections : XML file, CSV file, SQL Server, ODBC, Oracle Database, Excel … Have a look at this documentation page for further details. Multiple connections can be used in a single package.

在数据流中,我们通常从源(提取)中获取数据,我们最终对这些数据进行处理(转换)并将其存储到目的地(加载)。 源和目标由连接定义。 有各种各样的连接:XML文件,CSV文件,SQL Server,ODBC,Oracle数据库,Excel…请查看此文档页面以获取更多详细信息。 单个包装中可以使用多个连接。

Defining and editing connections is performed using a component of SSIS called « Connection Manager ».

定义和编辑连接是使用称为“连接管理器”的SSIS组件执行的。

Here are the connections defined in our example package.

这是示例包中定义的连接。

During the creation, we will set properties that describe the physical connection to be used during the execution of this package. Amongst those properties, we will find the kind of connection (Excel, CSV, etc.) and the connection string.

在创建过程中,我们将设置属性,以描述在执行此包期间要使用的物理连接。 在这些属性中,我们将找到连接的类型(Excel,CSV等)和连接字符串。

Recommendation

建议

When you define connection strings to a database instance or to a host…

当您定义到数据库实例或主机的连接字符串时…

  1. Use DNS aliases instead of IP Address or actual server name. This simplifies change management.

    使用DNS别名代替IP地址或实际服务器名称。 这简化了变更管理。

  2. Set the ApplicationName property whenever it’s possible. This will allow you to simplify debugging and tracing. For instance, in SQL Server Profiler, you will be able to filter on that particular ApplicationName. I recommend setting this property in any application you develop.

    尽可能设置ApplicationName属性。 这将使您简化调试和跟踪。 例如,在SQL Server Profiler中,您将能够在该特定ApplicationName上进行过滤。 我建议在您开发的任何应用程序中设置此属性。

Identifier property

标识符属性

Each package has a unique identifier, the GUID. As an example, you will find ID for our demo Package.

每个程序包都有一个唯一的标识符 GUID。 例如,您将找到我们演示包的ID。

This identifier is generated at creation and can be generated at any time, on demand. This identifier is used for logging and some other available functions. You will find below the way to generate a new identifier : you simply click on the arrow next to the current Id then on “<Generate New ID>”.

该标识符是在创建时生成的,可以根据需要随时生成。 该标识符用于记录日志和其他一些可用功能。 您将在下面找到生成新标识符的方法:您只需单击当前ID旁边的箭头,然后单击“ <Generate New ID>”。

A lot of SSIS developers have the common habit that consists in creating a package template. The advantage is that they can reuse it for their future developments. A problem with this practice is that they don’t necessarily generate a new GUID. If that happens, multiple packages can share the same GUID, leading to a headache in case of debugging (when SSIS logging is used) !

许多SSIS开发人员都有创建软件包模板的习惯。 优点是他们可以将其重新用于未来的发展。 这种做法的一个问题是它们不一定生成新的GUID。 如果发生这种情况,则多个软件包可以共享同一个GUID,从而在调试时(使用SSIS日志记录时)令人头疼!

Recommendation

建议

If you defined a package template, don’t forget to generate a new GUID for the newly created package based on that template.

如果定义了程序包模板,请不要忘记根据该模板为新创建的程序包生成新的GUID。

Variables and configurations

变量和配置

In every SSIS package, we can define variables. Here are some variables defined in our demo package :

在每个SSIS包中,我们都可以定义变量 。 这是在我们的演示包中定义的一些变量:

As in any programming language, variables holds values available at runtime. For instance, the User ::ErrorCount variable will hold the number of errors that occurred during execution.

与任何编程语言一样,变量保留在运行时可用的值。 例如, User :: ErrorCount变量将保存执行期间发生的错误数。

Another common usage of variables consists in keeping connection strings that are generated based, for instance, on the content of a SQL Server table.

变量的另一种常见用法是保留连接字符串,这些字符串是基于(例如)SQL Server表的内容生成的。

Generally, variables come along with SSIS Package configurations. They are defined as follows :

通常,变量随SSIS软件包配置一起提供。 它们的定义如下:

A configuration is a property/value pair that you add to a completed package.

配置是您添加到完整包中的属性/值对。

Package organization: folders

包裹组织:文件夹

Finally, last but not least thing to know, packages can be grouped in package folders. We can build a more or less complex hierarchy or simply group packages by project or by functionality. For instance :

最后,要了解的最后但并非最不重要的一点是,可以将分组在包文件夹中 。 我们可以建立或多或少复杂的层次结构,或仅按项目或功能对包进行分组。 例如 :

Description of a SSIS Package file

SSIS软件包文件的描述

Let’s say our package is ready (or saved but still under development), we can build it anyway. This operations results in the creation of a ‘dtsx’ file. This file is actually an XML file that completely describes the SSIS package (flows, variables, connections…). You will find an example of its contents below.

假设我们的软件包已准备就绪(或已保存,但仍在开发中),我们仍然可以构建它。 该操作导致创建“ dtsx”文件。 该文件实际上是一个完整描述SSIS包(流程,变量,连接…)的XML文件。 您将在下面找到其内容的示例。


<?xml version="1.0"?>
<DTS:Executable xmlns:DTS="www.microsoft.com/SqlServer/Dts" DTS:ExecutableType="SSIS.Package.2">
<DTS:Property DTS:Name="PackageFormatVersion">3</DTS:Property>
<DTS:Property DTS:Name="VersionComments"></DTS:Property>
<DTS:Property DTS:Name="CreatorName"></DTS:Property>
<DTS:Property DTS:Name="CreatorComputerName"></DTS:Property>
<DTS:Property DTS:Name="CreationDate" DTS:DataType="7">5/14/2003 8:58:00 AM</DTS:Property>
<DTS:Property DTS:Name="PackageType">0</DTS:Property>
<DTS:Property DTS:Name="ProtectionLevel">0</DTS:Property>
<DTS:Property DTS:Name="MaxConcurrentExecutables">-1</DTS:Property>
<DTS:Property DTS:Name="PackagePriorityClass">0</DTS:Property>
<DTS:Property DTS:Name="VersionMajor">1</DTS:Property>
<DTS:Property DTS:Name="VersionMinor">0</DTS:Property>
...

As for any well-formed XML, there is a corresponding XML Schema Definition a.k.a. « XSD ». For those who are not used to this term, here is a definition from Wikipedia:

对于任何格式正确的XML,都有一个相应的XML模式定义,也称为“ XSD”。 对于那些不习惯这个术语的人,这是维基百科的定义:

XSD (XML Schema Definition), a recommendation of the World Wide Web Consortium (W3C), specifies how to formally describe the elements in an Extensible Markup Language (XML) document. It can be used by programmers to verify each piece of item content in a document. They can check if it adheres to the description of the element it is placed in.

XSD(XML模式定义)是万维网联盟(W3C)的推荐,它指定如何正式描述可扩展标记语言(XML)文档中的元素。 程序员可以使用它来验证文档中的每个项目内容。 他们可以检查它是否符合放置元素的说明。

The corresponding definition can be seen on this page.

相应的定义可以在此页面上看到。

SSIS management objects (in msdb database)

SSIS管理对象(在msdb数据库中)

In this article, we extract information on SSIS packages that are stored in msdb database. For that purpose, Microsoft provided us three tables. You will notice that only two of them are relievant to be used in the following of this article.

在本文中,我们提取有关msdb数据库中存储的SSIS包的信息。 为此,Microsoft向我们提供了三个表。 您会注意到,在本文的以下内容中,只有两个是可缓解的。

  • dbo.sysssispackages :

    dbo.sysssispackages :

    Contains one row for each package that is saved to Microsoft SQL Server. There is a column called packagedata which is an exact copy of the content of the ‘dtsx’ file used for deployment.

    对于保存到Microsoft SQL Server的每个程序包,包含一行。 有一个称为packagedata的列,该列是用于部署的“ dtsx”文件内容的精确副本。

  • dbo.sysssispackagefolders :

    dbo.sysssispackagefolders :

    Contains one row for each logical folder in the folder hierarchy that Microsoft SQL Server Integration Services uses.

    Microsoft SQL Server集成服务使用的文件夹层次结构中的每个逻辑文件夹包含一行。

  • dbo.sysssislog :

    dbo.sysssislog :

    Contains one row for each logging entry that is generated by packages or their tasks and containers at run time.

    对于程序包或其任务和容器在运行时生成的每个日志记录条目,包含一行。

How to run a SSIS package using SQL Server Agent

如何使用SQL Server代理运行SSIS包

Running a SQL Server Integration Services Package using SQL Server Agent consists of creating and scheduling a SQL Server Agent Job of type « SSIS ». Once created, you can either run it when desired or let it run automatically (based on the schedules you defined).

使用SQL Server代理运行SQL Server Integration Services程序包包括创建和计划“ SSIS”类型SQL Server代理作业。 创建后,您可以根据需要运行它,也可以让它自动运行(根据您定义的时间表)。

For those of you who are interested of a more straight forwards procedure, I advice you to have a look at the following MSDN page: Schedule a Package by using SQL Server Agent.

对于那些对更直接的过程感兴趣的人,建议您查看以下MSDN页面: 使用SQL Server Agent计划程序包 。

Anyway, SQL Server Agent will just take the role of an interface to a command line tool called « dtutil ». You will find on the documentation page (dtutil Utility ) of this tool that it takes a /SourceServer parameter, which allows you to perform calls to remote SSIS management.

无论如何,SQL Server代理将只充当名为dtutil的命令行工具的接口。 在此工具的文档页面( dtutil Utility )上,您会发现它带有/ SourceServer参数,该参数允许您执行对远程SSIS管理的调用。

收集什么? (What to collect?)

We are now at a point where we should define the questions we can and we want to answer.

现在,我们应该定义我们可以并且想回答的问题。

You will find such a list in the table below. The purpose of this list is not to be exhaustive, but feel free to contact me with suggestions.

您可以在下表中找到这样的列表。 此列表的目的不是详尽无遗,但请随时与我联系以提出建议。

Must Have Should Have Could Have Wont Have
# Question
1 Which SSIS packages are deployed on a server, in which folder ? X
2 Who is the owner of a given SSIS Package ? X
3 What storage capacity does a given package take ? X
4 What is the version of a given package ? X
5 What connections are defined in a given package ? X
6 What providers are used in Connection Manager ? X
7 Which variables are defined in a given package ? X
8 Which package configurations are defined in a given package ? X
9 Which packages are run using a SQL Server Agent Job ? X
10 Does the SSIS Package Owner meet enterprise standards ? X
11 Are there packages with connections that does not meet enterprise standards ?
For instance, references to local server should be pointed out.
X
12 Are there Agent jobs running SSIS Packages that does not meet enterprise standards ?
For instance, references to local server should be pointed out.
X
一定有 应该有 可能有 不会有
1个 哪些SSIS包部署在服务器上的哪个文件夹中? X
2 谁是给定的SSIS程序包的所有者? X
3 给定的包装需要多少存储容量? X
4 给定软件包的版本是什么? X
5 给定包中定义了哪些连接? X
6 连接管理器中使用了哪些提供程序? X
7 给定包中定义了哪些变量? X
8 给定的包装中定义了哪些包装配置? X
9 使用SQL Server代理作业运行哪些程序包? X
10 SSIS包所有者是否符合企业标准? X
11 是否有连接不符合企业标准的软件包?
例如,应该指出对本地服务器的引用。
X
12 是否有运行不符合企业标准的SSIS程序包的代理作业?
例如,应该指出对本地服务器的引用。
X

Based on these questions and everything we discussed above, we can list the following actions :

基于这些问题以及上面讨论的所有内容,我们可以列出以下操作:

我们将如何收集数据? (How will we collect data ?)

Well, while the target is well known, we still need to take the time to answer the following question : « how will we do it ? ».

好吧,尽管目标很明确,但我们仍然需要花时间回答以下问题:«我们将如何做? »。

Actually, the answer will be pretty « simple ». As we’ve seen in a previous section, there is a column called packagedata in the dbo.sysssispackages table (stored in msdb database). While this table will allow us to list SSIS packages (action 1), the packagedata column can be used as input to extract attributes of a SSIS package like the connections (action 2). In fact, the content of this column is an XML and SQL Server provides everything we need to analyze/query XML. It’s the XQuery language that is part of T-SQL. This language is not the subject of this article, so it won’t be fully coverred. If you are interested in this subject, please refer to the following page on Microsoft’s documentation website : Introduction to XQuery in SQL Server 2005 or on the page describing all the T-SQL Methods to query XML Data Type.

实际上,答案将很简单。 正如我们在上一节中所看到的, dbo.sysssispackages表(存储在msdb数据库中)中有一列称为packagedata的列。 虽然此表使我们可以列出SSIS包(操作1),但packagedata列可用作输入来提取SSIS包的属性(如连接)(操作2)。 实际上,此列的内容是XML,而SQL Server提供了我们分析/查询XML所需的一切。 XQuery语言是T-SQL的一部分。 该语言不是本文的主题,因此不会被完全覆盖。 如果您对此主题感兴趣,请参考Microsoft文档网站上的以下页面: SQL Server 2005中的XQuery简介或描述所有查询XML数据类型的T-SQL方法的页面。

As you may expect, we won’t use XQuery to get the list of SQL Agent jobs that run SSIS packages. Why ? Simply because it’s not stored in packagedata column and not even in dbo.sysssispackages. Instead, we will query tables related to SQL Server Agend, also in msdb :

如您所料,我们不会使用XQuery来获取运行SSIS包SQL Agent作业的列表。 为什么呢 只是因为它没有存储在packagedata列中,甚至没有存储在dbo.sysssispackages中 。 相反,我们将在msdb中查询与SQL Server Agend相关的表:

  • msdb.dbo.sysjobs msdb.dbo.sysjobs
  • msdb.dbo.sysjobsteps msdb.dbo.sysjobsteps

The last action that remains (action 4) will exploit the results of prior actions, but’s it’s not part of this article.

剩下的最后一个动作(动作4)将利用先前动作的结果,但这不是本文的一部分。

In summary, here is the algorithm that we will follow :

总而言之,这是我们将遵循的算法:


$PkgList = "Extract the list of SSIS Packages (with definition XML)" ;
Store $PkgList TO <UserTable> ;
Foreach $P in $PkgList {"Extract the list of Connections in $P and store in <UserTable1>" ;"Extract the list of SQL Server agent jobs steps using $P" ;"Analyze collected data";
}

行动1:提取SSIS包的列表 (Action 1 : Extract the list of SSIS packages)

To extract the list of SSIS Packages, we will obviously use the msdb.dbo.sysssispackages table. This table alone should be enough, but if you want to get the full path of a given SSIS Package, there is some more work to do. This table contains a folderid column that refers to the key column with the same name in msdb.dbo.sysssispackagefolders table. Folders can be structured and have a parent folder. So we can find paths like /Finance/Billing or /CRM/Customers.

要提取SSIS软件包列表,我们显然将使用msdb.dbo.sysssispackages表。 仅此表就足够了,但是如果您要获取给定SSIS包的完整路径,则还有更多工作要做。 该表包含一个folderid列,该列引用msdb.dbo.sysssispackagefolders表中具有相同名称的键列。 文件夹可以结构化并具有父文件夹。 因此,我们可以找到/ Finance / Billing或/ CRM / Customers之类的路径。

As we have this unique identifier for a given folder, we can take advandtage of Common Table Expression (CTE) feature and query recursion to get the full path of a given SSIS Package.

由于我们具有给定文件夹的唯一标识符,因此可以利用通用表表达式 (CTE)功能和查询递归来获取给定SSIS包的完整路径。

Let’s review the structure of target query. There is the CTE declaration followed by the actual SELECT query:

让我们回顾一下目标查询的结构。 CTE声明后跟实际的SELECT查询:


with ChildFolders
as (<FirstLevelQuery>UNION ALL<SelfRecursiveQuery>
)
SELECT <ListOfColumns>
INTO <TemporaryTable>
FROM ChildFolders

Let’s first review the details of a target temporary table that will hold the results of the query. You will find below the TSQL statements to create such a table.

首先,让我们回顾一下将保存查询结果的目标临时表的详细信息。 您将在TSQL语句下面找到创建这样的表。


IF(OBJECT_ID('tempdb..#SSISPackagesList') IS NOT NULL)
BEGINEXEC sp_executesql N'DROP TABLE #SSISPackagesList';
END;CREATE TABLE #SSISPackagesList (PackageUniqifier        BIGINT IDENTITY(1,1) NOT NULL,PackageRunningId        NVARCHAR(50)   NOT NULL,RootFolderName          VARCHAR(256)   NOT NULL,ParentFolderFullPath    VARCHAR(4000)  NOT NULL,PackageOwner            VARCHAR(256)   NOT NULL,PackageName             VARCHAR(256)   NOT NULL,PackageDescription      VARCHAR(4000)      NULL,isEncrypted             BIT            NOT NULL,PackageFormat4Version   CHAR(4)        NOT NULL,PackageType             VARCHAR(128)   NOT NULL,CreationDate            DATETIME       NULL,PackageVersionMajor     TINYINT        NOT NULL,PackageVersionMinor     TINYINT        NOT NULL,PackageVersionBuild     INT            NOT NULL,PackageVersionComments  VARCHAR(4000)  NOT NULL,PackageSizeKb           BIGINT             NULL,PackageXmlContent       XML                NULL
);

The following table maps the columns created in last T-SQL statement with the answers we need to provide.

下表将上一条T-SQL语句中创建的列与我们需要提供的答案进行映射。

# Question List of columns
1 Which SSIS packages are deployed on a server, in which folder ? /td>
  • PackageRunningId
  • ParentFolderFullPath
  • PackageName
  • PackageDescription
2 Who is the owner of a given SSIS Package ?
  • PackageOwner
3 What storage capacity does a given package take ?
  • PackageSizeKb
4 What is the version of a given package ?
  • PackageVersionMajor
  • PackageVersionMinor
  • PackageVersionBuild
  • PackageVersionComments
列清单
1个 哪些SSIS包部署在服务器上的哪个文件夹中? / td>
  • PackageRunningId
  • ParentFolderFullPath
  • 包裹名字
  • 包装说明
2 谁是给定的SSIS程序包的所有者?
  • 包所有者
3 给定的包装需要多少存储容量?
  • 包装尺寸Kb
4 给定软件包的版本是什么?
  • PackageVersionMajor
  • PackageVersionMinor
  • PackageVersionBuild
  • PackageVersion评论

Note

注意

While the PackageRunningId column could be used as the primary key for this table. I would not recommend it and suggest, as I did with PackageUniqifier, to add another identifier (like an IDENTITY column), because of a common habits to use a template SSIS package without generating a new identifier.

而PackageRunningId列可用作此表的主键。 我不建议这样做,也不建议像我对PackageUniqifier所做的那样 ,添加另一个标识符(例如IDENTITY列),这是因为使用模板SSIS包而不生成新标识符的常见习惯。

There are other columns we also keep as they might be useful one day. For instance, the isEncrypted column may allow us to pinpoint the need to extract a certificate or to get a password used to encrypt this package. We will also take other columns for eventual analysis.

我们还会保留其他专栏,因为它们可能有一天会有用。 例如, isEncrypted列可能使我们指出需要提取证书或获取用于加密此程序包的密码。 我们还将采用其他专栏进行最终分析。

Now we know which information is needed, we will take the time to build the query that will fill the #SSISPackagesList temporary table step by step.

现在我们知道需要哪些信息,我们将花一些时间来构建查询,以逐步填充#SSISPackagesList临时表。

First, we’ll get the list of « root-level packages folders », i. e. folders that are created at the root of folders hierarchy. Notice that the following parameters are used :

首先,我们将获得“根目录包文件夹”列表,即在文件夹层次结构根目录下创建的文件夹。 请注意,使用了以下参数:

  • @RootLabel will keep the string to be used as root label. For instance « / ».
  • @RootLabel将保留该字符串用作根标签。 例如 ” / ”。
  • @SeparatorChar will keep the folder separator character to be used.
  • @SeparatorChar将保留要使用的文件夹分隔符。

Query 1 – get root-level packagesselect PARENT.parentfolderid, PARENT.folderid, PARENT.foldername,cast(@RootLabel as sysname) as RootFolder,cast(CASE WHEN (LEN(PARENT.foldername) = 0) THEN @SeparatorChar ELSE PARENT.foldername END as varchar(max)) as FullPath,0 as Lvlfrom msdb.dbo.sysssispackagefolders PARENTwhere PARENT.parentfolderid is null

The previous query will bring back the minimal set of folders, the first-level folders. It corresponds to the <FirstLevelQuery> tag introduced previously. Notice that there is a FullPath column that retains the full path of the folder (which is exactly what we want to get at the moment). To initiate recursion, we will take the union of this minimal set with another SELECT statement. This statement will use the msdb.dbo.sysssispackagefolders table joined with the CTE itself based on equality between the value of folderid column of this table and the value of parentfolderid column in CTE. It corresponds to the <SelfRecursiveQuery> tag.

上一个查询将带回最小的文件夹集,即第一级文件夹。 它对应于前面介绍的<FirstLevelQuery>标记。 请注意,这里有一个FullPath列,保留了文件夹的完整路径(这正是我们目前想要的路径)。 要启动递归,我们将这个最小集合与另一个SELECT语句结合使用。 该声明将使用与CTE本身加入了msdb.dbo.sysssispackagefolders台基于该表的folderid列的值和parentfolderid列的CTE值之间的平等。 它对应于<SelfRecursiveQuery>标记。


select CHILD.parentfolderid, CHILD.folderid, CHILD.foldername,case ChildFolders.Lvlwhen 0 then CHILD.foldernameelse ChildFolders.RootFolderend as RootFolder,cast(CASE WHEN (ChildFolders.FullPath = @SeparatorChar) THEN '' ELSE ChildFolders.FullPath END + @SeparatorChar + CHILD.foldername as varchar(max))as FullPath,ChildFolders.Lvl + 1 as Lvlfrom msdb.dbo.sysssispackagefolders CHILDinner join ChildFolders on ChildFolders.folderid = CHILD.parentfolderid

Finally, we can get back the list of SSIS packages with their full path in folder hierarchy. The next statement is the complete T-SQL query that fills up #SSISPackagesList temporary table.

最后,我们可以获取SSIS软件包的列表以及它们在文件夹层次结构中的完整路径。 下一条语句是填充#SSISPackagesList临时表的完整T-SQL查询。


with ChildFolders
as (select PARENT.parentfolderid, PARENT.folderid,PARENT.foldername,cast(@RootLabel as sysname) as RootFolder,cast(CASE WHEN (LEN(PARENT.foldername) = 0) THEN @SeparatorChar ELSE PARENT.foldername END as varchar(max)) as FullPath,0 as Lvlfrom msdb.dbo.sysssispackagefolders PARENTwhere PARENT.parentfolderid is nullUNION ALLselect CHILD.parentfolderid, CHILD.folderid, CHILD.foldername,case ChildFolders.Lvlwhen 0 then CHILD.foldernameelse ChildFolders.RootFolderend as RootFolder,cast(CASE WHEN (ChildFolders.FullPath = @SeparatorChar) THEN '' ELSE ChildFolders.FullPath END + @SeparatorChar + CHILD.foldername as varchar(max)) as FullPath,ChildFolders.Lvl + 1 as Lvlfrom msdb.dbo.sysssispackagefolders CHILDinner join ChildFolders on ChildFolders.folderid = CHILD.parentfolderid
)
INSERT INTO #SSISPackagesList (PackageRunningId,RootFolderName,ParentFolderFullPath,PackageOwner,PackageName,PackageDescription,isEncrypted,PackageFormat4Version,PackageType,CreationDate,PackageVersionMajor,PackageVersionMinor,PackageVersionBuild,PackageVersionComments,PackageSizeKb,PackageXmlContent
)
SelectCONVERT(NVARCHAR(50),P.id) As PackageId,F.RootFolder,F.FullPath,SUSER_SNAME(ownersid) as PackageOwner,P.name as PackageName,P.[description] as PackageDescription,P.isencrypted as isEncrypted,CASE P.packageformatWHEN 0 THEN '2005'WHEN 1 THEN '2008'ELSE 'N/A'END AS PackageFormat,CASE P.packagetypeWHEN 0 THEN 'Default Client'WHEN 1 THEN 'SQL Server Import and Export Wizard'WHEN 2 THEN 'DTS Designer in SQL Server 2000'WHEN 3 THEN 'SQL Server Replication'WHEN 5 THEN 'SSIS Designer'WHEN 6 THEN 'Maintenance Plan Designer or Wizard'ELSE 'Unknown'END as PackageType,P.createdate as CreationDate,P.vermajor,P.verminor,P.verbuild,P.vercomments,DATALENGTH(P.packagedata) /1024 AS PackageSizeKb,cast(cast(P.packagedata as varbinary(max)) as xml) as PackageData
from ChildFolders F
inner join msdb.dbo.sysssispackages P
on P.folderid = F.folderid
order by F.FullPath asc, P.name asc
; 

行动2:提取已定义的连接和连接提供程序的列表 (Action 2 : Extract the list of defined connection and connection providers)

Here is the part of the XSD which defines the expected contents of a XML describing a SSIS package. It’s taken from 5.1 DTS XSD.

这是XSD的一部分,它定义了描述SSIS包的XML的预期内容。 它取自5.1 DTS XSD 。


<xs:simpleType name="BasePropertyNameEnum"><xs:restriction base="xs:string"><xs:enumeration value="Description"/><xs:enumeration value="DTSID"/><xs:enumeration value="CreationName"/><xs:enumeration value="ObjectName"/></xs:restriction></xs:simpleType><xs:simpleType name="ConnectionManagerPropertyNameEnum"><xs:union memberTypes="DTS:BasePropertyNameEnum"><xs:simpleType><xs:restriction base="xs:string"><xs:enumeration value="DelayValidation"/></xs:restriction></xs:simpleType></xs:union>
</xs:simpleType><xs:simpleType name="ConnectionManagerObjectDataPropertyNameEnum"><xs:restriction base="xs:string"><xs:enumeration value="Retain"/><xs:enumeration value="ConnectionString"/><xs:enumeration value="FileUsageType"/><xs:enumeration value="Format"/><xs:enumeration value="LocaleID"/><xs:enumeration value="Unicode"/><xs:enumeration value="HeaderRowsToSkip"/><xs:enumeration value="HeaderRowDelimiter"/><xs:enumeration value="ColumnNamesInFirstDataRow"/><xs:enumeration value="RowDelimiter"/><xs:enumeration value="DataRowsToSkip"/><xs:enumeration value="TextQualifier"/><xs:enumeration value="CodePage"/><xs:enumeration value="ServerName"/><xs:enumeration value="UseFile"/><xs:enumeration value="UseEncryption"/><xs:enumeration value="RetainData"/></xs:restriction></xs:simpleType>

Let’s review some fields that I find interesting for further lookup.

让我们回顾一些我认为对进一步查找有趣的字段。

First of all, there is a Retain property that you can set to « True » if you want to share this connection accross multiple tasks in a given package. It means that if it’s not set to « True », SSIS will create a new connection everytime it has to use it.

首先,如果要在给定程序包中的多个任务之间共享此连接,则可以将Retain属性设置为“ True”。 这意味着,如果未将其设置为“ True”,则SSIS每次必须使用它时都会创建一个新连接。

The ConnectionString property is the most interesting one as it’s the actual descriptor of the connection.

ConnectionString属性是最有趣的属性,因为它是连接的实际描述符。

Furthermore, when we edit a new connection, we can tell SSIS to delay the validation of this connection until run time. We will then use the DelayValidation property.

此外,当我们编辑一个新的连接时,我们可以告诉SSIS将这个连接的验证推迟到运行时。 然后,我们将使用DelayValidation 属性 。

Finally, there are two base properties ObjectName and Description that can be useful

最后,有两个基本属性ObjectName和Description可能有用

This leads to the design of this temporary table :

这导致了此临时表的设计:


CREATE TABLE #StagingPackageConnStrs (PackageUniqifier    BIGINT NOT NULL,DelayValidation     VARCHAR(100),ObjectName          VARCHAR(256),ObjectDescription   VARCHAR(4000),Retain              VARCHAR(100),ConnectionString    VARCHAR(MAX));

And here is the T-SQL statement we can use to populate this table, based on the content of previous #SSISPackagesList temporary table.

这是基于先前#SSISPackagesList临时表的内容的T-SQL语句,我们可以用来填充该表。


WITH XMLNAMESPACES ('www.microsoft.com/SqlServer/Dts' AS pNS1, 'www.microsoft.com/SqlServer/Dts' AS DTS
) -- declare XML namespaces
INSERT INTO #StagingPackageConnStrs (PackageUniqifier,DelayValidation,ObjectName,ObjectDescription,Retain,ConnectionString
)
SELECT PackageUniqifier,CASE WHEN SSIS_XML.value('./pNS1:Property [@pNS1:Name="DelayValidation"][1]', 'varchar(100)') = 0 THEN 'False' WHEN SSIS_XML.value('./pNS1:Property [@pNS1:Name="DelayValidation"][1]', 'varchar(100)') = -1 THEN 'True'ELSE SSIS_XML.value('./pNS1:Property [@pNS1:Name="DelayValidation"][1]', 'varchar(100)') END AS DelayValidation,SSIS_XML.value('./pNS1:Property[@pNS1:Name="ObjectName"][1]','varchar(100)') AS ObjectName,SSIS_XML.value('./pNS1:Property[@pNS1:Name="Description"][1]',  'varchar(100)') AS ObjectDescription,CASE WHEN  SSIS_XML.value('pNS1:ObjectData[1]/pNS1:ConnectionManager[1]/pNS1:Property[@pNS1:Name="Retain"][1]', 'varchar(MAX)') = 0 THEN 'True'WHEN SSIS_XML.value('pNS1:ObjectData[1]/pNS1:ConnectionManager[1]/pNS1:Property[@pNS1:Name="Retain"][1]', 'varchar(MAX)') = -1 THEN 'False'ELSE SSIS_XML.value('pNS1:ObjectData[1]/pNS1:ConnectionManager[1]/pNS1:Property[@pNS1:Name="Retain"][1]', 'varchar(MAX)')END AS Retain,
SSIS_XML.value('pNS1:ObjectData[1]/pNS1:ConnectionManager[1]/pNS1:Property[@pNS1:Name="ConnectionString"][1]', 'varchar(MAX)') AS ConnectionString
FROM #SSISPackagesList PackageXML
CROSS APPLY PackageXMLContent.nodes ('/DTS:Executable/DTS:ConnectionManager') AS SSIS_XML(SSIS_XML)
;

Well, as you can see above, to get data about connections, you «  CROSS APPLY » with XML nodes of type ‘/DTS:Executable/DTS:ConnectionManager’.

好了,正如您在上面看到的那样,要获取有关连接的数据,请使用类型为'/ DTS:Executable / DTS:ConnectionManager'的 XML节点进行“ 交叉应用 ” 。

It’s not difficult to understand that you will do the exact same thing to extract information about either package configuration or variables :

不难理解,您将做完全相同的事情来提取有关程序包配置或变量的信息:

  • For configurations, nodes will be of type ‘/DTS:Executable/DTS:Configuration’.
  • 对于配置,节点的类型将为'/ DTS:Executable / DTS:Configuration' 。
  • For variables, nodes will be of type ‘/DTS:Executable/DTS:Configuration’.
  • 对于变量,节点将为'/ DTS:Executable / DTS:Configuration'类型 。

行动3:提取SSIS类型SQL Server代理作业的列表 (Action 3 : Extract the list of SQL Server Agent Jobs of SSIS type)

While previous action is a little bit more complex, the following one is pretty straightforwards. It consists more or less in a query against msdb.dbo.sysjobs and msdb.dbo.sysjobsteps tables. While the title of this section tends to say we are going to build a list of SQL Agent jobs, we actually will build a list of SQL Agent Job Steps. The first list is easy to get from second.

尽管上一个动作稍微复杂一点,但是下一个动作非常简单。 它或多或少包含在对msdb.dbo.sysjobs和msdb.dbo.sysjobsteps表的查询中。 尽管本节的标题倾向于说我们将建立一个SQL Agent作业列表,但实际上我们将建立一个SQL Agent作业步骤列表。 第一个列表很容易从第二个列表中获取。

As always, let’s review which columns will compose our target temporary table.

与往常一样,让我们​​回顾一下哪些列将构成目标临时表。

We will first identity the corresponding SSIS package that is used for a given step. To do so, there is the GUID of the package to identify the package. We know that this is not perfect and we might change this by a unique identifier generated at run time.

我们将首先标识用于给定步骤的相应SSIS包。 为此,有包装的GUID可以识别包装。 我们知道这并不完美,我们可以通过在运行时生成的唯一标识符来更改此设置。

We also will get back some general informations about the job :

我们还将获得有关这项工作的一些一般信息:

  • its identifier and name, 它的标识符和名称
  • whether this job is enabled or not, 无论是否启用此作业,
  • whether this job has already run or not 这项工作是否已经执行

Finally, as we get data on steps and not only jobs, we will collect the step id, the target server and the entire text of the command that composes the step.

最后,当我们获得有关步骤(不仅是作业)的数据时,我们将收集步骤ID,目标服务器以及组成该步骤的命令的整个文本。

You will find below the T-SQL statement to create the temporary table that will hold the list of SQL Agent job steps that call SSIS packages.

您将在T-SQL语句下方找到创建临时表的地方,该临时表将保存调用SSIS包SQL代理作业步骤的列表。


IF(OBJECT_ID('tempdb..#StagingPackageJobs') IS NOT NULL)BEGINEXEC sp_executesql N'DROP TABLE #StagingPackageJobs';END;CREATE TABLE #StagingPackageJobs (PackageUniqifier                BIGINT NOT NULL,JobId                           VARCHAR(128)   NOT NULL,JobName                         VARCHAR(256),JobStep                         INT            NOT NULL,TargetServerName                VARCHAR(512),FullCommand                     VARCHAR(MAX),isJobEnabled                    BIT,hasJobAlreadyRun                BIT);

And we still need a query to populate this table. It’s what the following query does.

而且我们仍然需要一个查询来填充此表。 这就是以下查询的作用。


WITH PkgList
AS (SELECT PackageUniqifier,CASE WHEN ParentFolderFullPath = '/' THEN '' ELSE ParentFolderFullPath END + '/' + PackageName as PackageFullPathFROM #SSISPackagesList
),
JobSteps
AS (SELECT CONVERT(VARCHAR(128),j.job_id)       as JobId,s.srvname      as AgentServerName,j.name         as JobName,js.step_id     as JobStepId,REPLACE(SUBSTRING(SUBSTRING(REPLACE(js.command,'\"',''),CHARINDEX('/SQL "',REPLACE(js.command,'\"','')) + LEN('/SQL "'),LEN(REPLACE(js.command,'\"',''))-CHARINDEX('/SQL "',REPLACE(js.command,'\"',''))-LEN('/SQL "')),0,CHARINDEX('"',SUBSTRING(REPLACE(js.command,'\"',''),CHARINDEX('/SQL "',REPLACE(js.command,'\"','')) + LEN('/SQL "'),LEN(REPLACE(js.command,'\"',''))-CHARINDEX('/SQL "',REPLACE(js.command,'\"',''))-LEN('/SQL "')))),'\','/')    as PackageFullPath,LOWER(SUBSTRING(SUBSTRING(REPLACE(js.command,'\"',''),CHARINDEX('/SERVER "',REPLACE(js.command,'\"','')) + LEN('/SERVER "'),LEN(REPLACE(js.command,'\"',''))-CHARINDEX('/SERVER "',REPLACE(js.command,'\"',''))-LEN('/SERVER "')),0,CHARINDEX('"',SUBSTRING(REPLACE(js.command,'\"',''),CHARINDEX('/SERVER "',REPLACE(js.command,'\"','')) + LEN('/SERVER "'),LEN(REPLACE(js.command,'\"',''))-CHARINDEX('/SERVER "',REPLACE(js.command,'\"',''))-LEN('/SERVER "'))))) as TargetServerName,js.command as FullCommand,CASE WHEN j.enabled = 1 THEN 1 ELSE 0 END as isJobEnabled,CASE WHEN js.last_run_date IS NULL THEN 0 ELSE 1 END as hasJobAlreadyRunFROM   msdb.dbo.sysjobs jJOIN   msdb.dbo.sysjobsteps jsON  js.job_id = j.job_id JOIN   master.dbo.sysservers sON  s.srvid = j.originating_server_id--filter only the job steps which are executing SSIS packages WHERE  subsystem = 'SSIS'
)
INSERT INTO #StagingPackageJobs (PackageUniqifier,JobId,JobName,JobStep,TargetServerName,FullCommand,isJobEnabled,hasJobAlreadyRun
)
SELECT  p.PackageUniqifier,s.JobId,s.JobName,s.JobStepId,s.TargetServerName,s.FullCommand,s.isJobEnabled,s.hasJobAlreadyRun
FROM PkgList p
INNER JOIN JobSteps s
ON p.PackageFullPath = s.PackageFullPath
;

摘要 (Summary)

We have seen that a SSIS Package is composed of multiple components and properties that can be extracted using different sources and techniques, especially the XML column called packagedata, in msdb.dbo.sysssispackages table and XQuery.

我们已经看到,SSIS包由多个组件和属性组成,可以使用不同的来源和技术来提取SSIS包,尤其是msdb.dbo.sysssispackages表和XQuery中称为packagedata的XML列。

The queries used in this article are grouped together in a SQL file you can download here.

本文中使用的查询归为一个SQL文件,您可以在此处下载。

下一步是什么 (What’s next)

We extracted some information. We can take these as input of an analysis process to pinpoint deviations to enterprise standards.

我们提取了一些信息。 我们可以将其作为分析过程的输入,以查明与企业标准的偏差。

参考资料 (References)

  • A full DTSX XSD 完整的DTSX XSD
  • SSIS technical documentation SSIS技术文档
  • Deploy Integration Services (SSIS) Projects and Packages 部署集成服务(SSIS)项目和程序包
  • T-SQL Methods to query XML Data Type 查询XML数据类型的T-SQL方法
  • Introduction to XQuery in SQL Server 2005 SQL Server 2005中的XQuery简介
  • Integration Services Connections 集成服务连接
  • Schedule a Package by using SQL Server Agent 通过使用SQL Server代理计划程序包

翻译自: https://www.sqlshack.com/how-to-retrieve-information-about-ssis-packages-stored-in-msdb-database/

msdb 数据库

msdb 数据库_如何检索有关存储在MSDB数据库中的SSIS包的信息相关推荐

  1. 2压缩备份数据库_为什么您的企业需要备份数据库

    数据是开展业务的重要组成部分.如果任何企业意外丢失数据,则可能导致巨大的损失.因此,为了保护有价值的信息,企业需要备份其数据库. 本文提供了有关数据库备份的重要性以及如何进行备份的所有信息. 什么是数 ...

  2. 阿里云怎样操作mysql数据库_阿里云主机如何操作mysql数据库

    阿里云主机如何操作mysql数据库,阿里云上传mysql数据库. 在阿里云ecs云服务器上部署数据库后,在平常的操作中可能会遇到些问题,可以先做个大致的了解: 如果您想看更多的在ecs上的数据库的相关 ...

  3. navicat怎么安装mysql数据库_【20170825】从零开始学SQL数据库 安装mysql与navicat,开始练习...

    封面已经说明一切.左边mysql确实很酷炫,时时刻刻感觉自己像个程序猿,但是还是右边的navicat美化过后的界面更友好一些. 网上关于如何安装这两个软件已经有很多教程了,我选择了一个比较新的,且非常 ...

  4. node本地连接服务器的数据库_基于Node.jsORM框架Sequelize的数据库迁移一

    开课吧Web前端教程 前言 在日常的后端项目开发中,我们经常需要和数据库打交道.在这个过程中,我们需要创建数据库.表还有一些测试数据.许多时候,因为业务需求的变更导致的数据库结构的变化,需要修改数据库 ...

  5. 爬取图片到mysql数据库_爬取微博图片数据存到Mysql中遇到的各种坑\mysql存储图片\爬取微博图片...

    前言 由于硬件等各种原因需要把大概170多万2t左右的微博图片数据存到Mysql中.之前存微博数据一直用的非关系型数据库mongodb,由于对Mysql的各种不熟悉,踩了无数坑,来来回回改了3天才完成 ...

  6. 阿里云数据库产品HybridDB简介——OLAP数据库,支持行列混合存储,基于数据库Greenplum的开源版本,并且吸收PostgreSQL精髓...

    为什么会有HybridDB的诞生?它经历了怎样的研发历程?它的应用场景和情况是怎样的?带着这些问题,InfoQ对阿里云的数据库专家兼Postgres中国社区/中国用户会主席萧少聪先生进行了采访,以下文 ...

  7. java创建mongdb数据库_【转发】Java使用MongoDB数据库进行增删改查

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_26584263/article/ ...

  8. 百度网盘 备份mysql数据库_利用百度云免费备份SQL数据库

    我们开发了一个会员管理系统,随着使用的人越来越多,异地备份数据库就显得十分重要,万一硬盘出问题了怎么办呢.所以就着手做这个工作. 首先呢,找到了几个专门用来提供备份数据库的网站,一年好几百,好贵.放弃 ...

  9. 比MySQL小的数据库_牛x!一个比传统数据库快 100-1000 倍的数据库!

    原标题:牛x!一个比传统数据库快 100-1000 倍的数据库! 一.ClickHouse 是什么? 二.业务问题 三.ClickHouse实践 四.遇到的坑 五.总结 一.ClickHouse 是什 ...

最新文章

  1. 如何判断一个元素在亿级数据中是否存在?
  2. R使用pROC和ggplot2包绘制ROC曲线
  3. Python的几种主动结束程序方式
  4. java 日期的工具类_java 日期时间工具类
  5. spring自动注入--------
  6. 开发VR游戏的基本要求
  7. 2010.11.25感恩节
  8. 看看别人后端API接口写得,那叫一个优雅!
  9. python多态实例_Python多态实例详解
  10. 山东大学高频电子线路实验四 振幅调制与解调实验详解
  11. 了解数据库(包括数据库发展史、分类、著名人物、主流数据库、关系与非关系型数据库)
  12. C++猜数字(文曲星游戏)
  13. 仿vivo控制中心下载_手机控制中心app
  14. 智能网联汽车信息安全研究报告
  15. 傻白入门芯片设计,wafer/die/chip/cell(一)
  16. 分析11.2.0.3 rac CRS-1714:Unable to discover any voting files
  17. 2010年最有价值做的16个广告联盟
  18. 基与坐标系(阅读《理解矩阵》笔记)
  19. 计算机的系统保护选项,右击“我的电脑”,属性选项,没有“系统还原”怎么处理啊?...
  20. 122.Linux系统和Shell命令行简介,走上数据分析之路

热门文章

  1. log4j配置时的位置问题
  2. 4538: [Hnoi2016]网络
  3. Lesson 013 —— python 数字
  4. QEMU+GDB调试方法
  5. react-navigation(6.0.6版本)使用详解(基于RN0.65*版本)
  6. 【Vue2.0】—Vue脚手架配置代理(二十二)
  7. 数据库原理—关系模型的基本概念(七)
  8. 钱花了才是自己的你们觉得这句话对吗?
  9. 白酒板块集体杀跌,我是不是该卖出手中的白酒基金了?
  10. 不要根据自己的喜好创业