我必须在数据库字段(/tmp/aaa/bbb
,C:\temp\xxx\yyy
等)中存储文件路径。我无法确定它们能存在多久。
鉴于此http://en.wikipedia.org/wiki/Comparison_of_file_systems和http://msdn.microsoft.com/en-us/library/aa365247.aspx,根据文件系统,理论上可能没有路径的长度限制。
我想将此字段定义为LONGBLOB
或VARCHAR(very high value)
并不明智。我想过像VARCHAR(1024)
这样的东西应该适用于最频繁(即使不是全部)的情况,而不是像DB字段那么大。你会推荐什么?
感谢。
答案 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中存储文件名都是浪费,并产生技术债务。
色谱柱的长度在性能方面非常重要。列长度直接影响:
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)
答案 5 :(得分:1)
该字段的长度应与一个字符串的长度相同。
当询问文件名的长度就像询问一些字符串的长度一样,询问路径的长度就像在一个未知大小的框中询问字符串的所有位的长度。
因此唯一明智的选择没有其他信息不限制长度,例如NVARCHAR(MAX)
答案 6 :(得分:-1)
我建议 VARCHAR(2048)甚至 VARCHAR(1024),因为文件路径通常不是2000个字符长。