我该如何找到SQL Server实例的数据目录?

82

我们有几个非常大的数据库(20GB+),其中大部分是静态查找数据。由于我们的应用程序会对这些数据库中的表执行连接操作,因此它们必须成为每个开发人员本地 SQL Server 的一部分(即它们不能托管在集中的共享数据库服务器上)。

我们计划复制一组规范化的实际 SQL Server 数据库文件(*.mdf 和 *.ldf 文件),并将其附加到每个开发人员的本地数据库。

最好的方法是什么,可以找出本地 SQL Server 实例的数据目录,以便我们可以将文件复制到正确的位置?这将通过自动化流程完成,因此我必须能够从构建脚本中找到并使用它。

15个回答

112

这取决于数据和日志文件是否设置了默认路径。

如果路径在 属性 => 数据库设置 => 数据库默认位置 中明确设置,则 SQL Server 将其存储在 Software\Microsoft\MSSQLServer\MSSQLServer 中的 DefaultDataDefaultLog 值中。

但是,如果这些参数没有被明确设置,SQL Server 将使用主数据库的数据和日志路径。

以下是涵盖两种情况的脚本。这是 SQL Management Studio 运行的查询的简化版本。

此外,请注意我使用的是 xp_instance_regread 而不是 xp_regread,因此该脚本适用于任何实例,包括默认实例和命名实例。

declare @DefaultData nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'DefaultData', @DefaultData output

declare @DefaultLog nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'DefaultLog', @DefaultLog output

declare @DefaultBackup nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'BackupDirectory', @DefaultBackup output

declare @MasterData nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg0', @MasterData output
select @MasterData=substring(@MasterData, 3, 255)
select @MasterData=substring(@MasterData, 1, len(@MasterData) - charindex('\', reverse(@MasterData)))

declare @MasterLog nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg2', @MasterLog output
select @MasterLog=substring(@MasterLog, 3, 255)
select @MasterLog=substring(@MasterLog, 1, len(@MasterLog) - charindex('\', reverse(@MasterLog)))

select 
    isnull(@DefaultData, @MasterData) DefaultData, 
    isnull(@DefaultLog, @MasterLog) DefaultLog,
    isnull(@DefaultBackup, @MasterLog) DefaultBackup

使用SMO可以实现相同的结果。下面是C#示例,但您也可以使用任何其他.NET语言或PowerShell。

using (var connection = new SqlConnection("Data Source=.;Integrated Security=SSPI"))
{
    var serverConnection = new ServerConnection(connection);
    var server = new Server(serverConnection);
    var defaultDataPath = string.IsNullOrEmpty(server.Settings.DefaultFile) ? server.MasterDBPath : server.Settings.DefaultFile;
    var defaultLogPath = string.IsNullOrEmpty(server.Settings.DefaultLog) ? server.MasterDBLogPath : server.Settings.DefaultLog;
}

如果你在SQL Server 2012及以上版本中设置了默认路径(这通常是正确的做法),那么使用起来要简单得多:

select 
    InstanceDefaultDataPath = serverproperty('InstanceDefaultDataPath'),
    InstanceDefaultLogPath = serverproperty('InstanceDefaultLogPath')

这不需要安装另一个软件包——SMO SDK吗? - BSalita
1
@BSalita - 如果您已经安装了SQL Server,那么您已经安装了SMO。您只需要引用C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies中的程序集,例如Microsoft.SqlServer.Smo.dllMicrosoft.SqlServer.ConnectionInfo.dll。但是,如果您从未安装SQL Server的机器上连接,则需要安装SMO。搜索“Microsoft SQL Server 2012 Feature Pack”以查找独立的SMO安装程序。 - Alex Aza
感谢您包含C#示例 - 那非常有帮助。 - TrailJon
2
它可以工作,但是我在结果中收到错误消息。RegQueryValueEx()返回错误2,“系统找不到指定的文件。” Msg 22001,Level 1,State 1 RegQueryValueEx()返回错误2,“系统找不到指定的文件。” Msg 22001,Level 1,State 1 - Dima Korobskiy
尝试在SQL 2005中识别此内容,但最后一个解决方案不起作用。然而,在搜索了整个注册表以查找您提到的任何关键字(例如“数据库默认位置”)之后,我无法在任何地方找到它 - 不管是SQL2005、SQL2008还是SQL2012。我在HKEY_LOCAL_MACHINE中搜索了该关键字的所有路径,但没有任何版本的痕迹。并且尝试通过TSQL进行操作时,我遇到了与@DKroot相同的错误。我想我只能欺骗并使用主数据库文件的目录了。 - Jerry Dodge

62

虽然这是一个非常旧的帖子,但我觉得我需要贡献一个简单的解决方案。 每当您知道在管理工作室中要访问用于任何类型的自动化脚本的参数的位置时,最简单的方法是在独立测试系统上运行快速分析器跟踪并捕获Management Studio在后端执行的操作。

在这种情况下,假设您有兴趣找到默认数据和日志位置,可以执行以下操作:

SELECT
  SERVERPROPERTY('instancedefaultdatapath') AS [DefaultFile],
  SERVERPROPERTY('instancedefaultlogpath') AS [DefaultLog]

33

我在SQL Server帮助文档的“创建数据库”语句中偶然发现了这个解决方案:

SELECT SUBSTRING(physical_name, 1, CHARINDEX(N'master.mdf', LOWER(physical_name)) - 1)
                  FROM master.sys.master_files
                  WHERE database_id = 1 AND file_id = 1

41
哇,出乎意料的是,这个不正确的答案居然得到了如此多的赞。这个查询将显示主数据库数据文件的路径,而不是默认数据文件路径。默认数据文件路径可能与master.mdf文件路径相同,也可能不同。如果您在大型生产环境中将用户数据库和系统数据库分开存储(这是常见情况),那么这个“解决方案”将无法使用。 - Alex Aza
@AlexAza 这比我想要的代码多得多,可能只是我的问题。 :-) 这个答案怎么样? - Aaron Jensen
快速评论 - 将SUBSTRING的starting_position值降至0,以获取完整的干净路径,而无需主master.mdf文件名的第一个字符。 - mojo
我们使用这个解决方案是因为我们不想打开注册表来获取答案。但是,我们在我们希望其他人创建的位置创建了一个数据库,并且我们正在寻找该数据库信息,而不是“master”。SELECT physical_name FROM sys.master_files mf inner JOIN sys.databases d ON d.database_id = mf.database_id AND d.name = 'our-template-database' AND TYPE = 0 - foxontherock
1
@AlexAza 我同意,这是一个不太好的解决方案,但对于旧版本的SQL Server,其他解决方案似乎不起作用,比如注册表。因此在你的答案中有评论。从注册表中读取似乎也像是一种黑客行为。 - Jerry Dodge

27

对于当前的数据库,您可以使用以下内容:

select physical_name fromsys.database_files;

如果要指定另一个数据库比如 'Model',请使用 sys.master_files:

select physical_name from sys.master_files where database_id = DB_ID(N'Model');


3
值得注意的是,这需要在您想要文件的数据库上下文中运行。(我曾经浪费了一些时间试图将其连接到 sysdatabases)。 - EM0
@EM0 不正确。您可以从任何地方查询 sys.master_files 并联接 sys.databasesselect * from sys.master_files f join sys.databases d on d.database_id = f.database_id - pim

18

从 Sql Server 2012 开始,您可以使用以下查询:

SELECT SERVERPROPERTY('INSTANCEDEFAULTDATAPATH') as [Default_data_path], SERVERPROPERTY('INSTANCEDEFAULTLOGPATH') as [Default_log_path];

(这是从http://technet.microsoft.com/en-us/library/ms174396.aspx的评论中引用并经过测试的。)


8

SQL Server的各个组件(数据、日志、SSAS、SSIS等)都有一个默认目录,可以在注册表中找到设置。了解更多信息,请参见:

http://technet.microsoft.com/zh-cn/library/ms143547(SQL.90).aspx

因此,如果您仅使用CREATE DATABASE MyDatabaseName创建数据库,则会在上述某个设置指定的路径上创建它。

现在,如果管理员/安装程序更改了默认路径,则实例的默认路径存储在注册表中:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\[INSTANCENAME]\Setup

如果您知道实例的名称,则可以查询注册表。以下示例是针对SQL 2008的,如果需要SQL2005路径,请告诉我。

DECLARE @regvalue varchar(100)

EXEC master.dbo.xp_regread @rootkey='HKEY_LOCAL_MACHINE',
        @key='SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLServer\Setup',
        @value_name='SQLDataRoot',
        @value=@regvalue OUTPUT,
        @output = 'no_output'

SELECT @regvalue as DataAndLogFilePath

当您使用适当的参数发出CREATE DATABASE DBName语句时,每个数据库都可以在其自己的位置上覆盖服务器设置进行创建。您可以通过执行sp_helpdb找到这一点。

exec sp_helpdb 'DBName'

这并没有帮助,因为我要查询的数据库还不存在。是否有一个相应的存储过程适用于实例(而不是数据库)? - Aaron Jensen
1
很抱歉,但这个解决方案是不正确的。在我第一次尝试时,这个注册表查询对我返回了“null”。我将“xp_regread”更改为“xp_instance_regread”,并修复了注册表路径“Software\Microsoft\MSSQLServer\Setup”,以使查询适用于每个SQL服务器实例,而不管版本如何。然而,查询返回的位置甚至与我的默认数据或日志文件位置相距甚远。此外,它为什么只返回数据和日志文件的一个值?在我的环境中,它们被设置为不同的值。在不同的磁盘上拥有数据和日志文件并不罕见。 - Alex Aza
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\[INSTANCENAME]\Setup 读取可以访问实例目录,但不能访问实际的数据/日志文件默认目录。它有 SQLDataRoot,但不包括子目录 \Data,这才是真正的位置。 - Jerry Dodge

6
保持简单:

让我们来说说技术:

use master
select DB.name, F.physical_name from sys.databases DB join sys.master_files F on DB.database_id=F.database_id

这将返回所有带有关联文件的数据库


2

从图形用户界面(GUI)入手:打开您的服务器属性,进入数据库设置,然后查看数据库默认位置

请注意,您可以将数据库文件放在任何地方,但保持它们在默认目录中似乎更为清晰。


1

小细节:没有数据文件夹,只有一个默认的数据文件夹。

无论如何,如果您想要安装第一个默认实例并找到它:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\Setup\SQLDataRoot

如果有命名实例,则 MSSQL.1 变成类似于 MSSQL10.INSTANCENAME。


这需要我知道 SQL Server 实例名称(例如 MSSQL.1、MSSQL.2、MSSQL._N_)。我该如何获取该实例名称? - Aaron Jensen
对于默认实例,它不是名称 - 只是数字。安装哪个实例取决于您!要查找已安装的实例,请查看HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL。 - Stu
我需要将我的数据库附加到其他应用程序实例所在的同一实例中。基本上,我需要将友好的实例名称(在SQL Server Enterprise Manager中显示,并且在所有计算机上都相同)转换为此内部“数字”标识符。 - Aaron Jensen
所以在实例名称中查找实例名称,查找标识符(即值),然后返回并查找适当的键。 - Stu

0
SELECT DISTINCT dbo.GetDirectoryPath(filename) AS InstanceDataPaths
FROM sys.sysaltfiles WHERE filename like '%.mdf' and filename not like '%\MSSQL\Binn\%'

SELECT DISTINCT dbo.GetDirectoryPath(filename) AS InstanceLogPaths
FROM sys.sysaltfiles WHERE filename like '%.ldf' and filename not like '%\MSSQL\Binn\%'

enter image description here

您可以从如何查找SQL Server实例的数据目录下载详细的SQL脚本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接