我发现我的大多数客户根本没有在记录他们的数据库,而且我觉得这很吓人。为了介绍一些更好的做法,我想知道人们在使用什么工具/流程。


如何记录数据库? (SQL-Server)
您使用什么工具?
数据库模式/元数据的文档存储格式?


Word文档
Excel电子表格
纯文本


文档化过程或策略是什么?

我不是在谈论逆向工程/对现有数据库进行文档化,而主要是在开发系统/数据库时的文档化最佳实践。 />

#1 楼

我一直在使用扩展属性,因为它们非常灵活。可以从MS_Description中删除大多数标准文档工具,然后您可以将其与定制工具一起使用。 br />
以及以下代码:http://code.google.com/p/caderoux/wiki/LeversAndTurtles

评论


您可以更改某些内容,而忘记相应地更改扩展属性,从而使它们不正确。您可以自动检测出这种差异吗?

–A-K
13 Mar 25 '13 at 0:43

至少,可以查询数据库模式(sys.tables / sys.columns)并保留其扩展属性(sys.extended_properties)的连接以标识未记录的字段,然后将该脚本转换为测试以在部署时运行。

–弥迦
16年2月18日在21:11

#2 楼

Microsoft的Visio Pro(直到Visio 2010)可以像CA的ERwin一样对数据库进行反向工程。 Visio是更便宜的选择,而ERwin是更详细,更完整的选择。如果人们不愿意去看扩展属性,那就更好了。您还可以使用Red Gate的SQL Doc之类的内容以HTML格式输出文档。

我发现了命名约定并正确设置了外键,从而导致了几乎是自记录的数据库。您仍然应该拥有一些外部文档,以更好地了解目的。

评论


一个简单的模式经常丢失的(即使是在一个命名良好且具有外键的数据库中)是对字段的描述。以我的经验,使所有字段都足够简单以适合列名是不寻常的。

– StockB
16年5月17日在19:54

为了强调这一点,像Visio或ApexSQL的Model这样的工具都依赖于定义所有外键关系。如果未定义它们,则这些工具会将表设置为它们自己的独立对象。因此,如果您继承了带有许多未定义外键的数据库,则free \ cheap工具不会有太多帮助。

– BCM
12月10日21:07

#3 楼

尝试SchemaSpy:http://schemaspy.sourceforge.net/

评论


我在钩子github.com/krismorte/database-diagrams下使用Schemaspy构建了一个项目

– Krismorte
4月13日19:55

#4 楼

对于SQL Server,我正在使用扩展属性。

通过以下PowerShell脚本,我可以为dbo模式中的单个表或所有表生成一个Create Table脚本。

该脚本包含一个Create table命令,主键和索引。外键作为注释添加。
表和表列的扩展属性作为注释添加。是的,支持多行属性。

脚本已调整为我的个人编码样式。


没有针对单个列的单独排序规则。
当前它需要Sql Server
身份验证。

下面是完整的代码,可以将扩展属性转换成一个很好的普通旧ASCII文档(顺便说一句,重新创建表是有效的sql):

function Get-ScriptForTable
{
    param (
        $server, 
        $dbname,
        $user,
        $password,
        $filter
    )

[System.reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo")  | out-null

$conn = new-object "Microsoft.SqlServer.Management.Common.ServerConnection" 
$conn.ServerInstance = $server
$conn.LoginSecure = $false
$conn.Login = $user
$conn.Password = $password
$conn.ConnectAsUser = $false
$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $conn

$Scripter = new-object ("Microsoft.SqlServer.Management.Smo.Scripter")
#$Scripter.Options.DriAll = $false
$Scripter.Options.NoCollation = $True
$Scripter.Options.NoFileGroup = $true
$scripter.Options.DriAll = $True
$Scripter.Options.IncludeIfNotExists = $False
$Scripter.Options.ExtendedProperties = $false
$Scripter.Server = $srv

$database = $srv.databases[$dbname]
$obj = $database.tables

$cnt = 1
$obj | % {

    if (! $filter -or  $_.Name -match $filter)
    {
        $lines = @()
        $header = "---------- {0, 3} {1, -30} ----------"  -f $cnt, $_.Name
        Write-Host $header 

        "/* ----------------- {0, 3} {1, -30} -----------------"  -f $cnt, $_.Name
        foreach( $i in $_.ExtendedProperties)
        {
            "{0}: {1}" -f $i.Name, $i.value
        }
        ""
        $colinfo = @{}
        foreach( $i in $_.columns)
        {
            $info = ""
            foreach ($ep in $i.ExtendedProperties)
            {
                if ($ep.value -match "`n")
                {
                    "----- Column: {0}  {1} -----" -f $i.name, $ep.name
                    $ep.value
                }
                else
                {
                    $info += "{0}:{1}  " -f $ep.name, $ep.value
                }
            }
            if ($info)
            {
                $colinfo[$i.name] =  $info
            }
        }
        ""
        "SELECT COUNT(*) FROM {0}" -f $_.Name
        "SELECT * FROM {0} ORDER BY 1" -f $_.Name
        "--------------------- {0, 3} {1, -30} ----------------- */" -f $cnt, $_.Name
        ""
        $raw = $Scripter.Script($_)
        #Write-host $raw
        $cont = 0
        $skip = $false 
        foreach ($line in $raw -split "\r\n")
        {
            if ($cont -gt 0)
            {
                if ($line -match "^\)WITH ")
                {
                    $line = ")"
                }
                $linebuf += ' ' + $line -replace " ASC", ""
                $cont--
                if ($cont -gt 0) { continue }
            }
            elseif ($line -match "^ CONSTRAINT ")
            {
                $cont = 3
                $linebuf = $line
                continue
            }
            elseif ($line -match "^UNIQUE ")
            {
                $cont = 3
                $linebuf = $line
                $skip = $true
                continue
            }
            elseif ($line -match "^ALTER TABLE.*WITH CHECK ")
            {
                $cont = 1
                $linebuf = "-- " + $line
                continue
            }
            elseif ($line -match "^ALTER TABLE.* CHECK ")
            {
                continue
            }
            else
            {
                $linebuf = $line
            }
            if ($linebuf -notmatch "^SET ")
            {
                if ($linebuf -match "^\)WITH ")
                {
                    $lines += ")"
                }
                elseif ($skip)
                {
                    $skip = $false
                }
                elseif ($linebuf -notmatch "^\s*$")
                {
                    $linebuf = $linebuf -replace "\]|\[", ""
                    $comment = $colinfo[($linebuf.Trim() -split " ")[0]]
                    if ($comment) { $comment = ' -- ' + $comment }
                    $lines += $linebuf + $comment
                }
            }
        }
        $lines += "go"
        $lines += ""
        $block = $lines -join "`r`n"
        $block
        $cnt++
        $used = $false
        foreach( $i in $_.Indexes)
        {
            $out = ''
            $raw = $Scripter.Script($i)
            #Write-host $raw
            foreach ($line in $raw -split "\r\n")
            {
                if ($line -match "^\)WITH ")
                {
                    $out += ")"
                }
                elseif ($line -match "^ALTER TABLE.* PRIMARY KEY")
                {
                    break
                }
                elseif ($line -match "^ALTER TABLE.* ADD UNIQUE")
                {
                    $out += $line -replace "\]|\[", "" -replace " NONCLUSTERED", "" 
                }
                elseif ($line -notmatch "^\s*$")
                {
                    $out += $line -replace "\]|\[", "" -replace "^\s*", "" `
                    -replace " ASC,", ", " -replace " ASC$", "" `
                    <#-replace "\bdbo\.\b", "" #> `
                    -replace " NONCLUSTERED", "" 
                }
                $used = $true
            }
            $block = "$out;`r`ngo`r`n"
            $out
        }
        if ($used)
        {
            "go"
        }
    }
} 
}


您可以编写给定数据库的完整dbo模式的脚本

Get-ScriptForTable 'localhost'  'MyDB' 'sa' 'toipsecret'  |  Out-File  "C:\temp\Create_commented_tables.sql"


或过滤单个表

Get-ScriptForTable 'localhost'  'MyDB' 'sa' 'toipsecret' 'OnlyThisTable'


#5 楼

看一下SchemaCrawler-这是我设计的免费命令行工具,旨在满足您的需求。 SchemaCrawler生成包含所有数据库模式对象的文本文件。此文本输出被设计为易于阅读,并且可与其他服务器的类似输出进行区分。

在实践中,我发现输出数据库模式的文本文件在构建过程中完成时很有用。这样,您可以将文本文件检入源代码控制系统,并拥有有关模式随时间演变的版本历史记录。 SchemaCrawler也旨在从命令行自动执行此操作。

#6 楼

如果曾经写过,则文档由word文档组成。将包括几个关系图。表列表以及每个表的内容以及它与其他表的关系的简要说明。文档的一章包括安全设置:应用程序需要“用户”哪些权限?

通常,在我工作过的公司中,数据库文档仅在客户是执行审计的客户时才编写,这往往限制了财务和政府客户的使用。

免责声明:太多的开发人员认为代码是文档,我对此也感到内<。

评论


我发现与文档不紧密绑定的文档(例如,单独的Word文档,而不是自动生成的架构图+命名良好的数据库对象)存在的一个大问题是,该文档一定会被错误地排除,因为时间流逝。原因很简单:单独的文档可以有效地复制信息。如果没有自动的方法使其与源保持同步,它将很快变得过时。将其与从数据库实时生成模式图并从代码中提取适当注释的工具进行比较。

–尼克·查马斯(Nick Chammas)
2011年8月19日在20:24

#7 楼

我使用扩展属性和Red Gates SQL Doc。效果很好!

#8 楼

有趣的是,我想知道其他人也如何做到这一点。

在开发第一个大型数据库项目时,我发现Microsoft SQL Server Management Studio 10.0.1600.22支持可导出到的数据库图。 Word文档或其他文档软件,您可以在其中添加任意数量的文档详细信息。只需在SQL Management Studio上扩展连接的数据库,然后在对象资源管理器中右键单击“数据库图”,然后选择“新建数据库图”即可生成一个交互式图,该图将显示不同表之间的所有关系。您甚至可以指定要包含在图表中的表,这样,即使您只是试图逐个记录文档,图像也不会变得毫无疑问。将图像导出到任何其他编辑软件并根据需要进行注释。

我还建议在生成数据库的脚本中使用大量的/ comments /。

通常,写下大量内容的工作很多,但是从长远来看是个好主意,例如当您或其他可怜的灵魂回来更新您的创作时,多年后! :)

评论


我不使用SQL Server图,因为外键约束只是连接到表的某处,就像在ER图中一样。我更喜欢使用连接器来连接主键和外键字段。

–R。Schreurs
16年7月15日在11:43

#9 楼

我为所有对象设置了MS_description扩展属性,然后使用ApexSQL Doc记录了整个数据库。
我以前创建过HTML文档,但最近我更喜欢PDF

#10 楼

我使用数据建模工具是因为它们使我可以记录有关数据库的重要信息,而不是数据库中的“适合内容”。元数据,例如隐私/安全/敏感度问题,管理,治理等。

这些数据可能超出了文档化数据库的某些需求,但这些对企业和帮助他们管理数据非常重要。

正式的工具还可以帮助我管理存储在多个数据库/实例/服务器中的数据。这在我们的打包应用程序世界中从未如此真实。

#11 楼

对于记录sql服务器,我强烈建议您刚发布:

Kendal Van Dyke编写的使用Windows PowerShell的SQL Server和Windows文档

链接中的简要说明:

SQL Power Doc是Windows PowerShell脚本和模块的集合,这些脚本和模块可发现,记录和诊断SQL Server实例及其基础Windows OS和计算机配置。 SQL Power Doc可用于从SQL Server 2000到2012的所有版本的SQL Server,以及从Windows 2000和Windows XP到Windows Server 2012和Windows 8的所有版本的Windows Server和使用者Windows操作系统。SQLPower Doc也能够提供文档Windows Azure SQL数据库。

#12 楼

DB Dictionary Creator
是一个开源的数据库文档工具,具有不错的GUI和导出/导入选项。它使用扩展属性来存储文档。它还将为主键列和外键列生成自动描述。

评论


需要.NET Framework 4.0,并且仅适用于SQL Server和SQL Express

–kevinsky
2012年10月7日15:55

自2010年以来未维护

– LowDBA-约翰·麦考尔(John McCall)
7月8日下午16:13

#13 楼

确实,扩展属性(MS_Description)是必经之路。将这些描述作为元数据的一部分随时可用,不仅可以由文档生成器使用,而且(希望有一天)可以由提供“智能”功能的工具使用,例如出色的Softtree的SQL Assistant http://www.softtreetech.com/ isql.htm(上次我没有检查过)或内置于SQL Sever Management Studio的Intellisense(自sql2008起)

我还认为开发人员和DBA应当很容易添加这些注释,因为Tangurena和Nick Chammas正确地指出了-开发人员非常不愿保持文档更新并讨厌重复的工作-这是公平的,尤其对于一个受过在整个职业生涯中优化工作的人而言。因此,除非真的很容易在靠近源代码的位置更新文档,否则将无法正常工作。

有时我在网上搜索并没有找到解决方案,因此我写了LiveDoco(不免费,很抱歉),以简化操作。如果有兴趣,请在此处了解更多信息:http://www.livedoco.com/why-livedoco(网站/ LiveDoco于2020年5月4日已死)。

#14 楼

我们使用Dataedo创建数据字典,文档存储过程和函数。我们粘贴在Visio中创建的ERD。所有文档都存储在Dataedo元数据存储库(格式文本)中,我们将其导出为HTML以供内部使用,或者导出为PDF以供打印的文档。

我们将每个对象分配给一个模块,并将每个模块分配给一个模块人。 Dataedo随附了文档状态报告,因此我们可以判断是否需要记录新的列或表。

#15 楼

您可以在--文件中使用常规的.sql前缀注释。

好处包括文档与数据库模式的代码一起提供,您可以轻松地将其提交到版本控制系统(例如Git)。 br />
示例:

-- Table to store details about people.
-- See also: The customer table.
-- Note: Keep this data safe!
-- Todo: Add a email column.
CREATE TABLE Persons ( -- People in the registry
    PersonID int,
    LastName varchar(255), -- The person's last name
    FirstName varchar(255), -- The person's first name
    Address varchar(255), -- Address of residence
    City varchar(255) -- City of residence
);


也许您也可以使用XML。

-- <summary>
-- Table to store details about people.
-- </summary>
-- <column name="PersonID">The id column.</column>
-- <column name="LastName">The person's last name.</column>
-- <column name="FirstName">The person's first name.</column>
-- <column name="Address">Address of residence.</column>
-- <column name="City">City of residence.</column>
CREATE TABLE Persons (
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255)
);


您还可以使用类似于jsDoc / phpDoc的语法。

-- Table to store details about people.
-- @column {int} PersonID - The id column.
-- @column {varchar} LastName - The person's last name.
-- @column {varchar} FirstName - The person's first name.
-- @column {varchar} Address - Address of residence.
-- @column {varchar} City - City of residence.
-- @see {@link https://example.com/|Example}
-- @author Jane Smith <jsmith@example.com>
-- @copyright Acme 2018
-- @license BSD-2-Clause
-- @todo Add a column for email address.
-- @since 1.0.1
-- @version 1.2.3
CREATE TABLE Persons (
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255)
);


,或者可以使用MarkDown语法。

-- # Persons
-- Table to store details about **people**.
-- * `PersonID` - The id column.
-- * `LastName` - The person's _last_ name.
-- * `FirstName` - The person's _first_ name.
-- * `Address` - Address of residence.
-- * `City` - City of residence.
--
-- [I'm an inline-style link](https://www.example.com/)
--
-- | PersonID | LastName | FirstName | Address | City |
-- | ---------| -------- | --------- | ------- | ---- |
-- | 1        | Smith    | Jane      | N/A     | N/A  |
CREATE TABLE Persons (
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255)
);


#16 楼

多年来,在这里尝试了许多免费和付费解决方案之后,我用纯T-SQL创建了自己的开源解决方案,该解决方案在Github Flavor Markdown,sp_doc中输出文档,这是名为DBA MultiTool的较大的免费脚本套件的一部分。 。
通过T-SQL进行操作可降低依赖第三方应用程序,PowerShell模块/库等的复杂性,并利用扩展属性的内置功能使数据库能够自我描述。它可以轻松地挂接到自动化部署工作流中,以生成数据库的始终最新的视图。

数据库可能是复杂的,灾难性的事情。并非每个数据库管理员,开发人员或分析人员都有时间学习数据库的来龙去脉,以完成工作。更糟糕的是,很少有产品和更少的免费选项来帮助您以人类可读的格式呈现数据库。这意味着您现在拥有一个免费且可扩展的自文档数据库!

更新:现在也可以通过dbatools的Install-DbaMultiTool命令进行安装。

#17 楼

ERD图(数据库图)始终是我团队中最有用的图

但是有规则在我们创建的每个表和列的“属性”中写“ Decription”。

然后我们使用的软件名称是Enterprise Architect来记录带有所有TablesIndexesForeign Keys以及Columns和Description的Type



#18 楼

特别是对于MySQL,我们始终使用MySQL Workbench。我们在设计器中创建数据库设计,然后将其导出为可运行的SQL脚本。应用设计中的所有更改,然后运行生成的脚本,可以确保设计和实际数据库彼此之间完全同步,并且文档不会轻易过时。