【问题标题】:SQL Server 2005 slows down as I keep adding rows随着我不断添加行,SQL Server 2005 变慢
【发布时间】:2023-04-01 15:18:01
【问题描述】:

作为前言,我是使用 SQL Server 2005 的新手;我知道如何使用 SELECT、UPDATE、DELETE 和 INSERT 命令,仅此而已。我还在本地 PC 上使用 Express Edition(E8400 处理器、8GB DDR2-800、RAID 1 中的 2 个 640GB SATA-II 硬盘)

我有一个表,我设置了 8 列,都是 NVARCHAR(Max),我允许 Null。我在概念上知道主键是什么,但我没有主键(我也不知道如何设置主键)。

我正在开发的 VB.NET 程序正在从雅虎下载历史股票价格图表,用于现有的每个股票代码。我添加的前 50,000 行左右速度非常快。然后我去睡觉了,当我醒来时它还在运行——但是增加行的速度已经减慢了 waaaaaay;我注意到这在第 300,000 行左右。我一直希望行添加的速率随着时间的推移保持不变,但显然不是这样!

通过浏览其他 Stack Overflow 问题,我怀疑我的速度变慢与我糟糕的桌子设置有关。如果是这种情况,我应该首先从哪里开始解决这个问题,有没有什么好的资源可以阅读以开始?我希望这是我可以解决的简单问题:)

如果重要的话,这就是我添加行的方式:

cmdtext = "IF NOT EXISTS(SELECT DateStamp FROM DailyPrice WHERE (DateStamp = '" +     datestamp + "' AND Ticker = '" + ticker + "')) INSERT INTO DailyPrice (Ticker,OpenPrice,ClosePrice,HighPrice,LowPrice,AdjustedClose,Volume,DateStamp) VALUES('" + ticker + "','" + openprice + "','" + closeprice + "','" + highprice + "','" + lowprice + "','" + adjustedclose + "','" + volume + "','" + datestamp + "')"
                cmd = New SqlCommand(cmdtext, conn)
                howmanygotinserted = cmd.ExecuteNonQuery

我对 CSV 文件的每一行都进行了迭代,每个 CSV 文件大约有 30,000 行(我有超过 5000 行)。

【问题讨论】:

    标签: sql-server vb.net sql-server-2005 performance


    【解决方案1】:

    有 8 列,都是 NVARCHAR(Max)

    这是你的第一个问题。如果您告诉数据库您拥有什么类型的数据,并选择适用于您的数据的最小数据类型,那么数据库的效果最好。 NVARCHAR(Max) 是您可以做出的最低效的选择。

    我没有[主键](我也不知道如何设置)。

    这是你的第二个问题。在每次插入时,您都在检查是否已经插入了与某些列的另一行具有相同值的行。因为您没有告诉数据库索引这些列,所以它每次都必须检查整个表,因此随着表的增长,您的查询会变得越来越慢。要向现有表添加主键,您可以使用:

    ALTER TABLE table1 ADD CONSTRAINT pk_table1 PRIMARY KEY (Ticker, DateStamp)
    

    请参阅here 了解更多信息。

    【讨论】:

    • 仅修复数据类型就带来了巨大的改进!接下来我将实现主键!我真的很感谢大家的帮助,所有的答案都对我有所帮助——我希望我能全部接受!
    【解决方案2】:

    你至少有两个问题:

    1. 您的表可能缺少适当的索引;和
    2. 您可能正在事务中运行。

    您应该在 (Ticker,DateStamp) 上有一个索引,并且检查会快得多。话虽如此,我什至不会做那个检查。如果 INSERT 失败,它就会失败。没什么大不了的。

    如果您在事务中运行并且没有提交或保存点,那么在您插入行时临时存储空间会变得很大(因为数据库需要能够回滚任何更改)。每 1000 行左右提交一次。要么在事务中运行,要么不在事务中运行。

    现在,下一个问题是如何构造 INSERT 语句。您不想将字符串连接与参数一起使用。这是一个不好的做法(在 Web 应用程序中,这是 SQL 注入漏洞的一个重要原因)。看看Insert command with parameters 并使用类似的东西:

    INSERT INTO DailyPrice
    (Ticker,OpenPrice,ClosePrice,HighPrice,LowPrice,AdjustedClose,Volume,DateStamp)
    VALUES
    (@Ticker,@OpenPrice,@ClosePrice,@HighPrice,@LowPrice,@AdjustedClose,@Volume,@DateStamp)
    

    最后,您应该添加一个主键。您可以为此使用 (Ticker,DateStammp),但我个人更喜欢技术主键,即没有外部含义的主键。自增整数字段是最常见的例子。添加 (Ticker,DateSTamp) 作为主键将添加我上面提到的索引。真正发挥作用的是索引。

    【讨论】:

    • 我必须总的来说同意使用技术主键,但为此目的,它可能只会增加额外的不必要的开销。另一方面,时间戳并不是特别好的密钥。我实际上并不完全相信关系数据库是存储这些数据的好方法,因为没有关系,并且数据正在建模现实生活中基于连续时间的东西,而不是基于行的东西。但是当你有一把锤子时......我想它会起作用。
    • 虽然我的 VB 应用程序只是本地的,但我感谢您在参数方面的帮助!我的 ASP.Net 程序(与此无关)急需它 - 我将用参数重做!
    【解决方案3】:

    除了其他人所说的之外,您还有一个问题是一次插入一行。使用批量插入或 SSIS 包要好得多。切勿通过遍历行来插入(或更新或删除)大量数据。数据库旨在处理数据集,并且在这样做时性能要好得多。

    【讨论】:

      【解决方案4】:

      您应该做的第一件事是在您的表上创建一个索引。每次要添加新行时(由于 SELECT DateStamp FROM DailyPrice ... WHERE ... 语句),您都会导致一次完整的表扫描,以查找一些现有值。

      无论如何,由于您正在检查具有特定 DateStampTicker 值的记录,因此您可以制作 DateStampTicker 表的主键,这样,数据库将索引这两列,您不需要执行IF NOT EXISTS 部分...如果已经存在则插入将失败表中的给定键。但是请记住,这将导致您的 VB.Net 程序出现异常,因此您必须处理它。

      您可以做的另一件事是更改列的数据类型,特别是那些被索引的。您可以将 Ticker 更改为 nvarchar(X),其中 X 是某个固定值(例如,nvarchar(250),如果您可以估计要存储在那里的字符串的长度。您也可以将 DateStamp 更改为 DateTime

      【讨论】:

      • 我不知道我可以使用 2 个主键!感谢您的帮助!
      • 不能有两个主键。不过,您可以有一个使用两列的主键。
      • 啊,我误会了。在 SQL studio thingy 中,它显示了 2 个关键符号(每列一个),我认为这意味着 2 个初选。所以这基本上归结为主键(两列的配对)必须是唯一的。
      【解决方案5】:

      在数据库问题方面:

      • 您可以在这些列上使用add a unique index,而不是检查是否存在匹配DateStampTicker 的记录。这将迫使 RDBMS 在插入任何内容之前检查现有记录,并且它可能会比您当前的版本快很多,因为它将使用索引并为此进行了优化。
      • 使用一些真实的数据类型而不是NVARCHAR(MAX)。找出每一列的适当数据类型,并将varchar 列的最大长度减少到您实际期望在数据库中的长度。这应该会使 SELECT 和内置索引管理工作得更快。
      • 如果您使用参数化查询并简单地更改参数值,代码可能会快一点。这样,您不仅可以摆脱那种丑陋的字符串连接,而且如果您的 CSV 文件之一包含“奇怪”的数据,也不会遇到问题,即。一个 ' 字符,它会破坏您的 SQL 查询。

      不过,我还会仔细检查您的 CSV 阅读器代码。如果真正的问题甚至不是数据库而是您的应用程序需要太多内存并导致交换怎么办?

      我一直希望行添加的速率随着时间的推移保持不变,但显然不是这样!

      正如您已经发现的那样,事实并非如此 - 如果您对该表应用大量索引,它甚至可能会变得“更糟”,因为这些索引会减慢 INSERT 语句的速度。

      【讨论】:

        猜你喜欢
        • 2019-05-21
        • 2012-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-22
        相关资源
        最近更新 更多