SQL服务器中的巨大表(900万条记录)

时间:2011-04-26 18:10:27

标签: sql-server-2008 windows-7

我们的承保公司刚刚向我们发送了潜在客户的数据摘录。有900万行。行包括LeadID(guid),RawLeadXML(xml - 可能最大3-4kb)和LeadStatusID(int)。

我首先尝试添加自动编号整数,并将其作为此表的主键。好吧,它添加了字段,但无法使其成为主键(缓冲池中没有足够的可用内存。)

我需要做的是获取每条记录,逐个1,并获取XML,将其放入.Net中的XmlDocument对象中,删除我想要的所有字段(名字,姓氏等)并存储将信息解析到另一个表中。

我甚至无法运行此语句:select * from Leads其中id介于1和1000之间

如果我一次只选择1000条记录(从Leads中选择前1000条),那就可以了,但是如何在没有某种参考点的情况下选择接下来的1000条记录呢?

我的机器有4个处理器(2.53Ghz)和12 GB的RAM。它不是服务器,但它是一台强大的机器。我老实说,我不知道下一步该尝试什么。

编辑:我遗漏了原始文件实际上是MDF(和关联的LDF)文件,所以我只是在SQL Server中附加它们。

编辑2 :我搞砸了并说RawLeadXML列是XML - 它不是,它只是nvarchar(max)。老实说,我不知道有一个xml数据类型。

编辑3 :我甚至无法在此表上发出删除声明:“从leadid ='100a7927-5311-4f12-8fe3-95c079d32dd4'的引线中删除”爆炸:< / p>

Msg 802, Level 17, State 20, Line 2
There is insufficient memory available in the buffer pool.

我不知道下一步该做什么。这到底是怎么回事?世界上有成千上万的数据库,记录的数量超过了我的记录。

编辑4 :如果有人关心,以下解决方案均无效。我确信这是我机器的限制,绝对不是对我在下面收到的好答案的谴责。目前,我正在将压缩数据库(2.6 GB)传输到Rackspace中的服务器,然后我将尝试在该硬件上添加索引,希望不会关闭我们的生产服务器。一旦添加了索引,我希望我可以压缩数据库并将其恢复到我的本地计算机,然后能够实际使用它。

编辑5 :我的机器无法处理此尺寸的表格。我的机器有12 GB RAM,64位Windows 7专业版,四核2.53Ghz处理器,SSD驱动器等。它对于开发机器来说非常强大。它无法解决这个问题。

所以,我把数据库移到伦敦Rackspace的服务器上。 48 GB或那个内存,它能够添加我需要的索引。即使在那之后,我的机器也无法做任何对它有用的事情,所以我写了一个在伦敦运行的.Net程序,一次输出1000个记录,将它们解析到另一个表中,然后将原始记录标记为已处理。

一旦我这样做,我将不得不离开伦敦的数据库,因为我怀疑我可以在本地写出任何有意义的报告来反对这种怪异。这将使开发变得有趣。

摘要:我认为没有使用至少48 GB RAM的服务器类硬件(在我的情况下)处理这么大的数据集的好方法。

9 个答案:

答案 0 :(得分:9)

错误802并不意味着经典意义上的内存不足以进行分配(这将触发error 701)。 Error 802实际上表明缓冲池无法增长,这可能由于以下几个原因而发生:

  • max server memory设置明确阻止缓冲池增长,检查服务器设置。
  • x86虚拟地址空间限制被点击AWE is not enabled。检查您是否有x86(32位)实例,如果是,请检查 all 是否满足启用AWE的条件。

如果您仍未找到问题,请阅读How to use the DBCC MEMORYSTATUS command to monitor memory usage on SQL Server 2005(该文章同样适用于SQL Server 2008和2008 R2),并遵循相关指南,了解消耗内存的人/内容。< / p>

答案 1 :(得分:4)

900万行不是那么大,你可能没有LeadId列的索引。首先创建一个,但需要一些时间(不必是唯一的或主键)。 比用一个 第一次查询选择“TOP TOP 1000 LeadId,RawXML ORDER BY LeadId”。 记录最后的LeadId(MaxLeadId)值,使用 “选择前1000名LeadId,RawXML,其中LeadId&gt; MaxLeadId ORDER BY LeadId” 等等...

答案 2 :(得分:3)

添加列不是一种选择,因为添加auto-id也不起作用。 您需要将已更改/已清理的数据存储在新表中。 此表可能有一个auto-id和单独的列,用于从Xml中提取的数据。

将数据插入此表后,您可以从源表中删除原始行。 或者创建一个select语句,该语句排除GUID已经在新表中的行。

由于源表的行没有依赖或特定顺序,因此选择/处理行的顺序并不重要。

根据评论,建议使用SQL语句:

WHILE EXISTS(SELECT * FROM [source] [s] 
              WHERE NOT EXISTS(SELECT * FROM [destination] [d] WHERE [d].[leadId] = [s].[leadId]))
BEGIN
    INSERT INTO [destination] ([leadId], [RawLeadXML], [LeadStatusId])
        SELECT TOP 100 [s].[leadId], [s].[RawLeadXML], [s].[LeadStatusId]
        FROM [source] [s] 
        WHERE NOT EXISTS(SELECT * FROM [destination] [d] WHERE [d].[leadId] = [s].[leadId])
END

我已设置要插入的记录数为100.这应该可以节省内存使用量。

答案 3 :(得分:1)

你有备用磁盘吗? 也许在“TableAux”中创建相同的表结构,但是使用自动数字ID然后从表中执行插入...

从平面文件导入到TableAux中(如果它不是平面文件,首先导出它)是另一种方法。

获取寄存器的ID是优先使用它们的。

答案 4 :(得分:1)

怎么样?
  • 选择表格的第一行(前1个),将LeadID存储在var。
  • 将xml列的值加载到xml文档(.NET)
  • 使用xpath
  • 定位您需要的节点
  • 将此值插入新记录
  • 使用leadid从“主”表中删除记录(或将其标记为“已完成”)
  • 提交
  • 第1步

答案 5 :(得分:1)

通过row_number()和排名来做这个。

Take a look at this thread。它有基本概念,可以帮助您入门。

答案 6 :(得分:0)

如果这是一个平面文件,您是否可以获得前1000行,加载它们然后返回并根据GUID从文件中删除行,然后重复? (当然首先备份文件。)

此外,您可以尝试通过Integration Services包加载此文件,该软件包应该能够跟踪导入的位置,并且应该能够批量处理它们并保持在内存限制范围内。

答案 7 :(得分:0)

您最初获取提取的格式是什么?如果它是csv或某些,并且您不关心该xml片段中的其他信息,我将使用SSIS并完全跳过此中间表。原生XML类型有一些与之相关的开销,如果你只是想要粉碎一些xml然后丢弃它,就不需要招致它。

否则,您应该能够在sql查询中直接使用XML路径语句来将数据从一个表获取到另一个表。如果您尝试从设计器添加新的PK,它可能会在大型表上失败。您需要编写更改脚本并手动运行它们,并可能调整它们以提高效率。按现代标准来说,最终9米的行并不是那么庞大,但你必须通过9k以上的方式来思考。

答案 8 :(得分:0)

如何直接从Access数据库中将数据提取到文本文件中 - 然后您可以使用批量插入将其导入到您选择的RDBM中。

通过MSSQL中的链接表访问数据库并不理想。这里我们使用只读,仅向前记录集游标来一次遍历一行。

这是VBScript,所以它不会是最快的,但它应该有效。您必须为您的架构定制XML提取例程。


' Code run against a access DB with column RawLeadXML

Dim connection

Set connection = CreateObject("ADODB.Connection")
connection.Open "Driver={Microsoft Access Driver (*.mdb)}; DBQ=d:\path\to\file.mdb;"

Dim recs

' By default this is a read only, forward only cursor
Set recs = connection.Execute("SELECT * FROM Leads")

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim out
Set out = fso.OpenTextFile("d:\path\to\output.txt", 2, True)

Dim id

id = 0

While Not recs.EOF
    id = id + 1 
    out.Write CStr(id) ' write an ID counter
    out.Write ","
    ExtractFieldsFromXML recs.Fields("RawLeadXML").Value, out
    out.Write Chr(10) ' Linefeed
    recs.MoveNext
Wend

out.Close
recs.Close
connection.Close

' Extract data from the XML and write it to the stream
' separated by commas
Sub ExtractFieldsFromXML(xml, out)
    Dim doc

    Set doc = CreateObject("MSXML2.DOMDocument")

    MsgBox xml

    doc.loadXML xml

    out.Write doc.selectSingleNode("/xml/firstname").text
    out.Write ","
    out.Write doc.selectSingleNode("/xml/lastname").text

End Sub