日期:2014-05-16  浏览次数:20611 次

当数据库中的文件超过4G
DB: SQL Server 2000
OS: windows server 2003
   前几天测试部提一个问题单:在进行压力测试的时候,应用程序抛出异常。大体如下:
未能为数据库 'testdb' 中的对象 'content_info' 分配空间,因为文件 'PRIMARY' 已满。at net.sourceforge.jtds.jdbc.JtdsStatement.executeBatch(JtdsStatement.java:944) at xx.xx.jtds.BatchOperate.process(BatchOperate.java:45)。显然提示的是分配的空间已满,查看存放文件的磁盘空间还有相当的空余,但是发现数据文件(.dat)已经接近4G,查看文件系统,是fat32,在fat32下单个文件最大值是不能超过4G的,问题就出在这里了,如果是nfs肯定就不会出现问题了。
   在sql server2000中对于数据文件和事务日志文件一般建议是分开存放的,如下在建立数据库的时候是可以选择存放位置的但是一旦建立成功将不能修改。


在图中可以看出对于文件可以有两种方式:
  1.自增长,这种好处是不需要人工干预,文件会根据设置伴随插入的数据变大。缺点就是由于受文件系统的制约单个文件达到文件系统可以管理的单个文件的最大值后,将不能在增长,这样应用程序会出出错。
  2.设置限制文件的大小,可以设置最大为2G,那么在fat32文件系统下就不会出现文件系统不能支持的大文件了,但是这样的缺点就是,需要创建多个文件每个文件指定能增长的到的最大值 (因为sql server不会在一个文件达到最大值后自动创建新的文件,这个需要人工巡检)。

可以编写一个小程序尝试一下(设置数据库数据文件大小为2M,当所有数据文件大小都达到最大值后,必然报错)
如:(数据库驱动使用的jtds,sql server一定要升级到SP3以上哦,不然报不能建立连接,jtds要求SP3)
public class BatchOperate 
{

	public static void main(String[] args) 
	{
		Connection conn;
		Statement stmt;
		String sql = null;
		try 
		{
			Class.forName("net.sourceforge.jtds.jdbc.Driver");
			Enumeration drivers = DriverManager.getDrivers();
			while(drivers.hasMoreElements())
			{
				System.out.println(drivers.nextElement().getClass().getName());
			}
			System.out.println(DriverManager.getDriver("jdbc:jtds:sqlserver"));
			conn = DriverManager.getConnection("jdbc:jtds:sqlserver://192.168.1.101:1433/testdb", "sa", "sa");
			stmt = conn.createStatement();
			for(int i = 0; i < 1000000; i++)
			{
				sql = "insert into content_info values(" + i + 
		            ",'pippo25pippo25','ftp://192.168.1.5/media/1.wmv'," +
				    "'pippo25pippo25','pippo25pippo25',0,0,0)";
				stmt.addBatch(sql);
				if(i % 1000 == 0)
				{
					stmt.clearBatch();
				}
				stmt.executeBatch();
			}
			stmt.close();
			conn.close();
		} 
		catch (SQLException e) 
		{
			e.printStackTrace();
		} 
		catch (ClassNotFoundException e) 
		{
			e.printStackTrace();
		}
	}
}

  哪种方式更好,就取决于实际使用中的文件系统了。

  说到这里简单阐述一下几种文件系统:
  文件系统是操作系统用于明确磁盘或分区上的文件的方法和数据结构;即在磁盘上组织文件的方法。也指用于存储文件的磁盘或分区,或文件系统种类。因此,可以说"我有2个文件系统"意思是他有2个分区,一个存文件,或他用 "扩展文件系统",意思是文件系统的种类。
  文件系统是操作系统与驱动器之间的接口,当操作系统请求从硬盘里读取一个文件时,会请求相应的文件系统(FAT 16/32/NTFS)打开文件。扇区是磁盘最小的物理存储单元,但由于操作系统无法对数目众多的扇区进行寻址,所以操作系统就将相邻的扇区组合在一起,形成一个簇,然后再对簇进行管理。每个簇可以包括2、4、8、16、32或64个扇区。显然,簇是操作系统所使用的逻辑概念,而非磁盘的物理特性。

  为了更好地管理磁盘空间和更高效地从硬盘读取数据,操作系统规定一个簇中只能放置一个文件的内容,因此文件所占用的空间,只能是簇的整数倍;而如果文件实际大小小于一簇,它也要占一簇的空间。所以,一般情况下文件所占空间要略大于文件的实际大小,只有在少数情况下,即文件的实际大小恰好是簇的整数倍时,文件的实际大小才会与所占空间完全一致。
  为什么fat32只能单个文件大小不会超过4G?
  硬盘在没有进行格式化之前是不可以使用的,格式化就是要给他一个文件系统。FAT32文件系统管理一个文件需要FDT(File Directory Table)和FAt(File Allocation Table)两个表合作才能完成,首先在FDT表中会记录文件的创建时间、大小、文件名称、文件的第一FAT表项等等,每一个表项大小为32bit,注意喽使用32bit存储文件大小,这就是文件最大值是2^32(4G)大小了,终于知道为什么文件有4G的限制了。那么FAT表呢,FAT32顾名思义,每一个表项32bit,每一个表项对应磁盘卷上的每一个簇,这就是说表项数目=簇数目=磁盘卷大小/簇大小。这样文件存放的时候首先由FDT表存储文件第一簇占用的FAT表项的地址,这样就可以根据FDT表查找到了FAT表中的相应表项目,FAT表项存储文件存放下一个簇的表象地址,这样形成一个存储连,当到达文件末尾的时候在FAT最后一个表象中表示出来。
大体图像如下:

FAT表的下面代表表项地址,上面一行是表象中的内容记录的时下一个表象的地址,这样形成存储链
1 楼 魔力猫咪 2008-05-07  
古怪的问题。使用NTFS不就可以了吗。
2 楼 ray_linn 2008-05-09  
很显然,缺少数据库专家。