数据库设计:文件路径的首选字段长度

时间:2010-12-07 14:33:08

标签: sql-server database database-design

我必须在数据库字段(/tmp/aaa/bbbC:\temp\xxx\yyy等)中存储文件路径。我无法确定它们能存在多久。

鉴于此http://en.wikipedia.org/wiki/Comparison_of_file_systemshttp://msdn.microsoft.com/en-us/library/aa365247.aspx,根据文件系统,理论上可能没有路径的长度限制。

我想将此字段定义为LONGBLOBVARCHAR(very high value)并不明智。我想过像VARCHAR(1024)这样的东西应该适用于最频繁(即使不是全部)的情况,而不是像DB字段那么大。你会推荐什么?

感谢。

7 个答案:

答案 0 :(得分:15)

为您要支持的数据使用适当的长度。由于您使用的是SQL Server,因此应使用nvarchar(260)作为存储路径名的上限,因为that is the specification limit用于典型的Windows机器。在某些情况下,您可以创建比此更长的路径,但Windows资源管理器在处理它们时往往会遇到问题。 SQL Server无法处理超过260个字符的文件名。这包括Linux上的SQL Server。

我可以证明 SQL Server在内部使用nvarchar(260)列来存储SQL Server数据库文件名,并包含路径。检查sys.master_files视图的定义,我们看到以下T-SQL:

 CREATE VIEW sys.master_files AS
    SELECT
        database_id     = f.dbid,
        file_id         = f.fileid,
        file_guid       = f.fileguid,
        type            = f.filetype,
        type_desc       = ft.name,
        data_space_id   = f.grpid,
        name            = f.lname,
        physical_name   = f.pname,
        state           = convert(tinyint, case f.filestate     -- Map enum EMDFileState to AvailablityStates
                                when 0 then 0 when 10 then 0    -- ONLINE
                                when 4 then 7   -- DEFUNCT
                                when 5 then 3 when 9 then 3 -- RECOVERY_PENDING
                                when 7 then 1 when 8 then 1 when 11 then 1  -- RESTORING
                                when 12 then 4  -- SUSPECT
                                else 6 end),    -- OFFLINE
        state_desc      = st.name,
        f.size,
        max_size            = f.maxsize,
        f.growth,
        is_media_read_only  = sysconv(bit, f.status & 8),       -- FIL_READONLY_MEDIA
        is_read_only            = sysconv(bit, f.status & 16),  -- FIL_READONLY
        is_sparse           = sysconv(bit, f.status & 256), -- FIL_SPARSE_FILE
        is_percent_growth   = sysconv(bit, f.status & 32),  -- FIL_PERCENT_GROWTH
        is_name_reserved        = sysconv(bit, case f.filestate when 3 then 1 else 0 end), -- x_efs_DroppedReusePending
        create_lsn          = GetNumericLsn(f.createlsn),
        drop_lsn                = GetNumericLsn(f.droplsn),
        read_only_lsn           = GetNumericLsn(f.readonlylsn),
        read_write_lsn      = GetNumericLsn(f.readwritelsn),
        differential_base_lsn   = GetNumericLsn(f.diffbaselsn),
        differential_base_guid  = f.diffbaseguid,
        differential_base_time  = nullif(f.diffbasetime, 0),
        redo_start_lsn          = GetNumericLsn(f.redostartlsn),
        redo_start_fork_guid    = f.redostartforkguid,
        redo_target_lsn     = GetNumericLsn(f.redotargetlsn),
        redo_target_fork_guid   = f.forkguid,
        backup_lsn          = GetNumericLsn(f.backuplsn),
        credential_id       = cr.credential_id
    FROM sys.sysbrickfiles f
    LEFT JOIN sys.syspalvalues st ON st.class = 'DBFS' AND st.value = f.filestate
    LEFT JOIN sys.syspalvalues ft ON ft.class = 'DBFT' AND ft.value = f.filetype
    LEFT JOIN sys.credentials cr ON f.pname LIKE cr.name + N'%' COLLATE database_default
    WHERE f.dbid < 0x7fff -- consistent with sys.databases
        AND f.pruid = 0
        AND f.filestate NOT IN (1, 2)   -- x_efs_Dummy, x_efs_Dropped
        AND has_access('MF', 1) = 1

Microsoft Docs for sys.master_files说明physical_name列:

  

physical_name nvarchar(260)操作系统文件名。

但我们不相信。我们看到物理文件名称被引用为physical_name = f.pname。表别名“f”指向FROM sys.sysbrickfiles f。因此,SQL Server将文件名存储在sys.sysbrickfiles中,这是一个内部表,只能从专用管理员连接或DAC中看到,因为它是众所周知的。连接到DAC和sys.sysbrickfiles的{​​{3}},我们会看到以下内容:

CREATE TABLE #sysbrickfiles
(
      brickid           int              NOT NULL
    , dbid              int              NOT NULL
    , pruid             int              NOT NULL
    , fileid            int              NOT NULL
    , grpid             int              NOT NULL
    , status            int              NOT NULL
    , filetype          tinyint          NOT NULL
    , filestate         tinyint          NOT NULL
    , size              int              NOT NULL
    , maxsize           int              NOT NULL
    , growth            int              NOT NULL
    , lname             nvarchar(128)    NOT NULL
    , pname             nvarchar(260)    NOT NULL
    , createlsn         binary(10)       NULL
    , droplsn           binary(10)       NULL
    , fileguid          uniqueidentifier NULL
    , internalstatus    int              NOT NULL
    , readonlylsn       binary(10)       NULL
    , readwritelsn      binary(10)       NULL
    , readonlybaselsn   binary(10)       NULL
    , firstupdatelsn    binary(10)       NULL
    , lastupdatelsn     binary(10)       NULL
    , backuplsn         binary(10)       NULL
    , diffbaselsn       binary(10)       NULL
    , diffbaseguid      uniqueidentifier NULL
    , diffbasetime      datetime         NOT NULL
    , diffbaseseclsn    binary(10)       NULL
    , redostartlsn      binary(10)       NULL
    , redotargetlsn     binary(10)       NULL
    , forkguid          uniqueidentifier NULL
    , forklsn           binary(10)       NULL
    , forkvc            bigint           NOT NULL
    , redostartforkguid uniqueidentifier NULL
);

如您所见,pname列确实定义为nvarchar(260)

此外,如果我们尝试使用长度超过260个字符的文件名创建数据库,我们会看到返回错误:

  

Msg 103,Level 15,State 3,Line 7
  与启动文件“F:\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARGH.mdf”太长。最大长度为259。

使用nvarchar(260)列以外的任何内容在SQL Server中存储文件名都是浪费,并产生技术债务。

色谱柱的长度在性能方面非常重要。列长度​​直接影响:

  • 内存授予针对列的查询。当查询处理器创建查询计划时,它使用查询中存在的每个列的大小作为运行查询所需的内存量的基础。它不使用每列中存在的数据的实际大小,而是“猜测”数据的平均大小将是列的最大长度的50%。
  • 能够有效地索引列。较大的列会创建更大的索引。较大的索引需要比较小的索引更多的内存和磁盘吞吐量。对于非聚簇索引(从SQL Server 2016开始),SQL Server的最大密钥长度为1700字节,对于聚簇索引,SQL Server的最大密钥长度为900字节。如果您尝试在大于这些最大金额的列上创建索引,则会出现错误,并且可能直到运行时才能修复成本非常高。
  • 基于字符的主/外键性能受较大列长度的严重影响。当通过外键引用主键时,每个外键都会重复内存,磁盘和I / O的大小要求。以Customer表为例,其中键为CustomerName列,定义为varchar(500)。引用客户的每个表现在都需要一个500字节的CustomerName列。如果该列被定义为varchar(100),则引用这些列的每个查询将在内存和磁盘I / O中保存每行 200字节

答案 1 :(得分:9)

您可以使用VARCHAR(MAX)NVARCHAR(MAX)

这些是可变长度字段,意味着它们用于存储不同长度的值。对于较短的值,较长的值没有额外的开销。

定义MAX表示该字段最大可达2GB。

MSDN(varchar),nvarchar有类似的文档:

  

当列数据条目的大小变化很大时使用varchar。

     

当列数据条目的大小变化很大时,使用varchar(max),大小可能超过8,000字节。

答案 2 :(得分:8)

如果您使用SQL Server,最好知道Microsoft正在使用 nvarchar(260)字段在系统表中存储文件路径和名称(例如sys.database_files或{{ 3}},或sys.sysaltfiles)。

Column name      Data type        Description
-------------    -------------    ---------------------------
physical_name    nvarchar(260)    Operating-system file name.

良好的做法可能是使用相同的格式来存储您的路径和文件名。

您将当然,需要在UI中强制执行大小,以确保在INSERT或UPDATE期间不会截断它。

答案 3 :(得分:2)

我建议您不要在现有表中存储路径。创建一个新表,其中包含一个顺序计数器作为聚簇主键和一个db程序最大长度的字符列。我使用SQL Server,所以我会使用varchar(max)。

在数据表中创建一个列以保存“paths”表的主键。首先插入“paths”表,然后在数据表中使用主键作为外键。

将值存储在另一个表中的优点是它不会影响基表的数据大小。不涉及“路径”的基表查询不会产生大的字符值,从而增加了IO流量。

答案 4 :(得分:2)

无法预测文件路径的长度。它可能非常短'C:\',或者可能非常冗长,如'C:\Program Files\Microsoft SQL Server\110\LocalDB\Binn\Resources\1033'甚至更长。但是在数据库级别,使用VARCHAR(MAX)

之类的东西是没有害处的

See Maximum size of VARCHAR(MAX)

答案 5 :(得分:1)

该字段的长度应与一个字符串的长度相同。

当询问文件名的长度就像询问一些字符串的长度一样,询问路径的长度就像在一个未知大小的框中询问字符串的所有位的长度。

因此唯一明智的选择没有其他信息不限制长度,例如NVARCHAR(MAX)

答案 6 :(得分:-1)

我建议 VARCHAR(2048)甚至 VARCHAR(1024),因为文件路径通常不是2000个字符长。