作为序言,我是使用SQL Server 2005的新手;我知道如何使用SELECT,UPDATE,DELETE和INSERT命令以及它的相关信息。我也在我的本地PC上使用Express Edition(E8400处理器,8GB DDR2-800,RAID 1中的2 x 640GB SATA-II HDD)
我有一个用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行)。
答案 0 :(得分:7)
有8列,都是NVARCHAR(最大)
这是你的第一个问题。如果您告诉他们您拥有什么类型的数据,并选择适用于您的数据的最小数据类型,数据库最有效。 NVARCHAR(Max)是您可能做出的最低效的选择。
我没有[主键](也不知道如何设置一个)。
那是你的第二个问题。在每个插入上,您要检查是否已经插入了与某些列的另一行具有相同值的行。因为您没有告诉数据库索引这些列,所以每次都必须检查整个表,因此随着表的增长,查询会变得越来越慢。要将主键添加到现有表,您可以使用:
ALTER TABLE table1 ADD CONSTRAINT pk_table1 PRIMARY KEY (Ticker, DateStamp)
有关详细信息,请参阅here。
答案 1 :(得分:1)
你至少有两个问题:
你应该有一个索引(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)作为主键将添加我上面提到的索引。这是真正有所作为的指数。
答案 2 :(得分:1)
除了其他人所说的内容之外,您还遇到了一个问题,即您一次只能插入一行。使用批量插入或SSIS包更好。永远不要通过遍历行插入(或更新或删除)大量数据。数据库旨在处理各种数据集,并在执行此操作时表现更好。
答案 3 :(得分:0)
您应该做的第一件事是在表上创建索引。每次要添加新行时(由于SELECT DateStamp FROM DailyPrice ... WHERE ...
语句),您都会导致完整的表扫描,并查找某些现有值。
无论如何,由于您要检查每个插入的特定 DateStamp 和 Ticker 值的记录,您可以使 DateStamp 和 Ticker 您的表的主键,这样,数据库将索引这两列,您不需要执行IF NOT EXISTS
部分...如果存在,插入将失败已经是表中的给定键。但请记住,这会导致VB.Net程序出现异常,因此您必须处理它。
您可以做的另一件事是更改列的数据类型,特别是索引的数据类型。如果您可以估计要存储在其中的字符串的长度,则可以将 Ticker 更改为nvarchar(X)
,其中X为某个固定值(例如nvarchar(250
)。您也可以将 DateStamp 更改为DateTime
。
答案 4 :(得分:0)
就数据库问题而言:
DateStamp
和Ticker
匹配的记录。这将迫使RDBMS在插入任何内容之前检查现有记录,并且它可能比当前版本快得多,因为它将使用索引并针对此进行优化。NVARCHAR(MAX)
。找出每列的相应数据类型,并将varchar
列的最大长度减少到您实际期望在数据库中的大小。这应该使SELECTs和内置索引管理工作更快。'
字符会破坏您的SQL查询。但是,我还会仔细检查您的CSV阅读器代码。如果真正的问题甚至不是数据库但你的应用程序需要太多内存并导致交换怎么办?
我一直希望行添加的速率随着时间的推移而保持不变,但显然不是这样!
正如您已经发现的那样,它不是 - 如果您将大量索引应用于该表,它甚至可能会“变得更糟”,因为这样会减慢INSERT语句。