我最近问过这个问题: MS SQL在表格中共享身份种子 (很多人想知道为什么)
我有一个表格的以下布局:
表:星星
starId bigint
categoryId bigint
starname varchar(200)
但我的问题是我有数百万行.因此,当我想从表格中删除星星时,它在SQL Server上过于激烈.
我不能使用2005+的内置分区,因为我没有企业许可证.
当我删除时,我总是一次删除整个类别ID.
我想过做这样的设计:
表:Star_1
starId bigint
CategoryId bigint constaint rock = 1
starname varchar(200)
表:Star_2
starId bigint
CategoryId bigint constaint rock = 2
starname varchar(200)
通过这种方式,我可以通过执行简单的删除表来删除整个类别,从而删除O(1)中的数百万行.
我的问题是,在SQL Server中拥有数十万个表是一个问题吗?O(1)的下降对我来说是非常可取的.也许有一个完全不同的解决方案,我没想到?
编辑:
插入后是否曾经修改过星星?没有.
您是否需要查询星级类别?我永远不必查询星级类别.
如果您正在寻找特定星的数据,您会知道要查询的表吗?是
输入数据时,应用程序将如何决定将数据放入哪个表中?在创建categoryId时,在开始时一次性完成星形数据的插入.
有多少个类别?您可以假设将有无限的星级类别.假设每天最多100个星级类别,每天最多不需要30个星级类别.
你真的需要删除整个类别或只删除数据更改的星号吗?是全明星类别.
您是否尝试过分批删除?是的,我们今天这样做,但还不够好.够了.
另一种技术是将记录标记为删除?没有必要将星标记为已删除,因为我们知道整个星级类别都有资格被删除.
他们中有多少比例从未使用过?通常我们会将每个星级类别数据保留几周,但有时需要保留更多.
当你认为一个有用的是永远有用还是以后还需要删除?
不是永远,而是在发出删除类别的手动请求之前.如果是这样的话有多少时间会发生?不常见.
你使用什么样的光盘安排?单个文件组存储,当前没有分区.
你能用sql enterprise吗?没有.有很多人运行这个软件,他们只有sql标准.获得ms sql企业是超出预算的.
Aar*_*ght 34
我的问题是,在SQL Server中拥有数十万个表是一个问题吗?
是.在SQL Server中拥有这么多表是一个很大的问题.SQL Server必须将每个对象作为元数据进行跟踪,并且一旦包含索引,引用约束,主键,默认值等,那么您将讨论数百万个数据库对象.
虽然SQL Server理论上可以处理2 32个对象,但请放心,它会在负载之下开始屈服.
如果数据库没有崩溃,您的开发人员和IT人员几乎肯定会.当我看到超过一千张左右的桌子时,我感到紧张; 给我看一个数十万的数据库,我会跑掉尖叫.
创建数十万个表作为穷人的分区策略将使您无法执行以下任何操作:
SELECT多个类别?)另一方面,在一个表中拥有数十万行甚至数百万行并不是一个问题- 这就是SQL Server和其他SQL RDBMS设计使用的方式,它们非常好 -为这种情况优化.
O(1)的下降对我来说是非常可取的.也许有一个完全不同的解决方案,我没想到?
数据库中性能问题的典型解决方案是按优先顺序排列:
但这里的现实是,你并不需要一个"解决方案".
"数百万行"在SQL Server数据库中并不多.通过简单地索引要删除的列,可以非常快速地从数百万个表中删除几千行 - 在本例中CategoryID.SQL Server可以毫不费力地做到这一点.
实际上,删除通常具有O(M log N)复杂度(N =行数,M =要删除的行数).为了实现O(1)删除时间,您首先要牺牲SQL Server提供的几乎所有好处.
O(M log N)可能没有O(1)那么快,但是你所谈论的减速类型(删除几分钟)必须有次要原因.这些数字并没有加起来,为了证明这一点,我已经开始并制定了一个基准:
CREATE TABLE Stars
(
StarID int NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_Stars PRIMARY KEY CLUSTERED,
CategoryID smallint NOT NULL,
StarName varchar(200)
)
CREATE INDEX IX_Stars_Category
ON Stars (CategoryID)
Run Code Online (Sandbox Code Playgroud)
请注意,此模式甚至没有针对DELETE操作进行真正优化,它是您在SQL Server中可能看到的相当普遍的表模式.如果此表没有关系,那么我们不需要代理键或聚簇索引(或者我们可以将聚簇索引放在类别上).我稍后再说.
这将使用500个类别(即每个类别1:20,000的基数)在表中填充1000万行.您可以调整参数以更改数据量和/或基数.
SET NOCOUNT ON
DECLARE
@BatchSize int,
@BatchNum int,
@BatchCount int,
@StatusMsg nvarchar(100)
SET @BatchSize = 1000
SET @BatchCount = 10000
SET @BatchNum = 1
WHILE (@BatchNum <= @BatchCount)
BEGIN
SET @StatusMsg =
N'Inserting rows - batch #' + CAST(@BatchNum AS nvarchar(5))
RAISERROR(@StatusMsg, 0, 1) WITH NOWAIT
INSERT Stars2 (CategoryID, StarName)
SELECT
v.number % 500,
CAST(RAND() * v.number AS varchar(200))
FROM master.dbo.spt_values v
WHERE v.type = 'P'
AND v.number >= 1
AND v.number <= @BatchSize
SET @BatchNum = @BatchNum + 1
END
Run Code Online (Sandbox Code Playgroud)
最简单的......
DELETE FROM Stars
WHERE CategoryID = 50
Run Code Online (Sandbox Code Playgroud)
这是在运行5年的工作站机器 IIRC,32位双核AMD Athlon和便宜的7200 RPM SATA驱动器上测试的.
我使用不同的CategoryID运行了10次测试.最慢的时间(冷缓存)大约是5秒.最快的时间是1秒.
也许没有简单地删除表那么快,但远不及你提到的多分钟删除时间.请记住,这甚至不是一台体面的机器!
关于您的问题的一切意味着这些数据不相关.如果您没有关系,则不需要代理键,并且可以删除其中一个索引,将聚簇索引移动到CategoryID列.
现在,作为一项规则,非唯一/非连续列上的聚簇索引不是一个好习惯.但我们只是在这里进行基准测试,所以无论如何我们都会这样做:
CREATE TABLE Stars
(
CategoryID smallint NOT NULL,
StarName varchar(200)
)
CREATE CLUSTERED INDEX IX_Stars_Category
ON Stars (CategoryID)
Run Code Online (Sandbox Code Playgroud)
在此上运行相同的测试数据生成器(产生令人难以置信的页面拆分数),同样的删除平均只有62毫秒,190个来自冷缓存(异常值).作为参考,如果索引是非聚簇的(根本没有聚簇索引),则删除时间最多只能达到606毫秒.
如果您看到几分钟的删除时间- 甚至几秒钟,那么事情就非常非常错误.
可能的因素是:
统计数据不是最新的(这里不应该是一个问题,但如果是,只需运行sp_updatestats);
缺乏索引(尽管奇怪的是,删除IX_Stars_Category第一个示例中的索引实际上会导致更快的整体删除,因为聚簇索引扫描比非聚簇索引删除更快);
选择不当的数据类型.如果你只有几百万行,而不是数十亿美元,那么你就不需要bigint在StarID.你肯定不需要它CategoryID- 如果你有少于32,768个类别,那么你甚至可以用a smallint.每行中不必要数据的每个字节都会增加I/O成本.
锁争用.也许问题实际上并不是删除速度; 也许其他一些脚本或进程Star在行上持有锁,DELETE只是坐在那里等待它们放手.
硬件非常差.我能够在一台非常糟糕的机器上运行这个没有任何问题,但是如果你在90年代的Presario或类似的机器上运行这个数据库,这些机器非常不适合托管SQL Server的一个实例,并且它负载很重那么你显然会遇到问题.
非常昂贵的外键,触发器,约束或您未在示例中包含的其他数据库对象,这可能会增加高成本.您的执行计划应该清楚地显示这一点(在上面的优化示例中,它只是一个Clustered Index Delete).
老实说,我想不出任何其他可能性.在SQL Server中删除并不是那么慢.
如果您能够运行这些基准并看到我看到(或更好)的大致相同的性能,那么这意味着问题在于您的数据库设计和优化策略,而不是SQL Server或删除的渐近复杂性.作为一个起点,我建议您阅读一些关于优化的内容:
如果这还不能帮助你,那么我可以提供以下补充建议:
升级到SQL Server 2008,它为您提供了无数的压缩选项,可以大大提高I/O性能;
考虑将每类别Star数据预压缩为紧凑的序列化列表(使用BinaryWriter.NET中的类),并将其存储在varbinary列中.这样,每个类别可以有一行.这违反了1NF规则,但是因为无论如何你似乎没有对Star数据库中的个人数据做任何事情,我怀疑你会失去太多.
考虑使用非关系数据库或存储格式,例如db4o或Cassandra.不是实现已知的数据库反模式(臭名昭着的"数据转储"),而是使用实际为这种存储和访问模式设计的工具.
| 归档时间: |
|
| 查看次数: |
3251 次 |
| 最近记录: |