将此数据模型存储为非关系型?
Store this data model as non-relational?
我目前处于一种情况,我想将我的一个经典关系数据库 table 重新设计为非关系设计,但我不确定是否应该这样做。原因是性能问题完全失控了。
这个table有11列,设计如下:
Id bigint (PK) -- Clustered Index
FK1 bigint (FK) -- Non-Clustered Unique Composite Index ( FK1_FK2_FK3 in this order )
FK2 bigint (FK) -- Non-Clustered Unique Composite Index ( FK1_FK2_FK3 in this order )
FK3 bigint (FK) -- Non-Clustered Unique Composite Index ( FK1_FK2_FK3 in this order )
Value1 nvarchar(100)
Value2 nvarchar(100)
Value3 nvarchar(100)
Value4 nvarchar(100)
Value5 nvarchar(100)
Value6 nvarchar(100)
Value7 nvarchar(100)
Value8 nvarchar(100)
以下是一些事实:
- 数据库 table 有 ~800.000.000 条记录并且增长速度比预期快
- 请求数量非常少,但每个请求的工作负载很高
5% 的请求如下所示:
SELECT *
FROM myTable
WHERE Id = 12346 -- (works perfectly)
SELECT *
FROM myTable
WHERE Id IN (123456, 654321) -- (works OK because IN list contains only a small number of IDs)
UPDATE myTable
SET .....
WHERE Id = 123456 (works perfectly)
不幸的是,95% 的请求看起来像这样:
SELECT *
FROM myTable
WHERE Fk1 = 123456 AND FK2 = 654321
-- works badly because it gets 100.000 - 300.000 records but I need all of them. Yes, unique index is used because order of index is correct )
UPDATE myTable
SET Value1 = '1', Value2 = '2', Value3 = '3', Value 4 = '4',
Value5 = '5', Value6 = '6', Value7 = '7', Value8 = '8'
WHERE Fk1 = 123456 AND FK2 = 654321 -- horrible because also 300.000 and yes, unique index is used because order of index is correct )
相反,我想这样设计它:
Id1 bigint (PK) -- Clustered Composite Index (former FK1 column)
Id2 bigint (PK) -- Clustered Composite Index (former FK2 column)
ContentColumn JSON -- Contains all former Value columns and the FK3 column as an array of objects. A object is column FK3, Value1, Value2 ....
ArrayLength INT -- length of json array
- 以前的 FK1 和 Fk2 现在是集群唯一复合 PK,因为 95% 的人都在选择和更新它
- 这当然意味着当我 运行 在我 5% 的情况下我必须加载比我实际需要的更多,但在我看来它仍然值得
- 我当然必须知道 Json FK3 在请求之前,但我这样做是因为一些其他逻辑
- 我也不需要复合唯一约束和FK3。
- FK3 的外键约束也不是必需的。
- 没有专门读取或搜索特定前值列的 SQL 形式,例如其中值 5 = 'ABC'
那么你们怎么看呢?我应该试一试吗?
或者你有什么完全不同的想法?
感谢您的帮助!
Or do you have some completely different ideas?
您可以使用一组更好的索引设计来做得更好。您想要针对最昂贵的查询进行优化:
SELECT *
FROM myTable
WHERE Fk1 = 123456 AND FK2 = 654321
-- works badly because it gets 100.000 - 300.000 records but I need all of them. Yes, unique index is used because order of index is correct )
UPDATE myTable
SET Value1 = '1', Value2 = '2', Value3 = '3', Value 4 = '4',
Value5 = '5', Value6 = '6', Value7 = '7', Value8 = '8'
WHERE Fk1 = 123456 AND FK2 = 654321
做成FK1_FK2_FK3聚簇索引,把ID做成non-clusteredPK会更好。对于检索少量行的查询,使用从 non-clustered PK 到复合聚集索引的嵌套循环连接应该没问题。但是在通过 (Fk1,Fk2) 进行查询时进行 300,000 次查找将非常昂贵。这些查询可能会进行 table 扫描,因为它非常昂贵。
并且在通过 (FK1,FK2,FK3) 对 table 进行聚类后,考虑通过 FK2 将其划分为 10-100 个单独的分区。那么像 WHERE Fk1 = 123456 AND FK2 = 654321
这样的谓词将只需要扫描包含 FK2=654321 的分区,并且可以在该分区中直接查找 FK1=123456 的第一页。
此外,如果 PAGEIOLATCH 等待是查询运行时的重要部分,请考虑 ROW 或 PAGE 压缩。
我目前处于一种情况,我想将我的一个经典关系数据库 table 重新设计为非关系设计,但我不确定是否应该这样做。原因是性能问题完全失控了。
这个table有11列,设计如下:
Id bigint (PK) -- Clustered Index
FK1 bigint (FK) -- Non-Clustered Unique Composite Index ( FK1_FK2_FK3 in this order )
FK2 bigint (FK) -- Non-Clustered Unique Composite Index ( FK1_FK2_FK3 in this order )
FK3 bigint (FK) -- Non-Clustered Unique Composite Index ( FK1_FK2_FK3 in this order )
Value1 nvarchar(100)
Value2 nvarchar(100)
Value3 nvarchar(100)
Value4 nvarchar(100)
Value5 nvarchar(100)
Value6 nvarchar(100)
Value7 nvarchar(100)
Value8 nvarchar(100)
以下是一些事实:
- 数据库 table 有 ~800.000.000 条记录并且增长速度比预期快
- 请求数量非常少,但每个请求的工作负载很高
5% 的请求如下所示:
SELECT *
FROM myTable
WHERE Id = 12346 -- (works perfectly)
SELECT *
FROM myTable
WHERE Id IN (123456, 654321) -- (works OK because IN list contains only a small number of IDs)
UPDATE myTable
SET .....
WHERE Id = 123456 (works perfectly)
不幸的是,95% 的请求看起来像这样:
SELECT *
FROM myTable
WHERE Fk1 = 123456 AND FK2 = 654321
-- works badly because it gets 100.000 - 300.000 records but I need all of them. Yes, unique index is used because order of index is correct )
UPDATE myTable
SET Value1 = '1', Value2 = '2', Value3 = '3', Value 4 = '4',
Value5 = '5', Value6 = '6', Value7 = '7', Value8 = '8'
WHERE Fk1 = 123456 AND FK2 = 654321 -- horrible because also 300.000 and yes, unique index is used because order of index is correct )
相反,我想这样设计它:
Id1 bigint (PK) -- Clustered Composite Index (former FK1 column)
Id2 bigint (PK) -- Clustered Composite Index (former FK2 column)
ContentColumn JSON -- Contains all former Value columns and the FK3 column as an array of objects. A object is column FK3, Value1, Value2 ....
ArrayLength INT -- length of json array
- 以前的 FK1 和 Fk2 现在是集群唯一复合 PK,因为 95% 的人都在选择和更新它
- 这当然意味着当我 运行 在我 5% 的情况下我必须加载比我实际需要的更多,但在我看来它仍然值得
- 我当然必须知道 Json FK3 在请求之前,但我这样做是因为一些其他逻辑
- 我也不需要复合唯一约束和FK3。
- FK3 的外键约束也不是必需的。
- 没有专门读取或搜索特定前值列的 SQL 形式,例如其中值 5 = 'ABC'
那么你们怎么看呢?我应该试一试吗?
或者你有什么完全不同的想法?
感谢您的帮助!
Or do you have some completely different ideas?
您可以使用一组更好的索引设计来做得更好。您想要针对最昂贵的查询进行优化:
SELECT *
FROM myTable
WHERE Fk1 = 123456 AND FK2 = 654321
-- works badly because it gets 100.000 - 300.000 records but I need all of them. Yes, unique index is used because order of index is correct )
UPDATE myTable
SET Value1 = '1', Value2 = '2', Value3 = '3', Value 4 = '4',
Value5 = '5', Value6 = '6', Value7 = '7', Value8 = '8'
WHERE Fk1 = 123456 AND FK2 = 654321
做成FK1_FK2_FK3聚簇索引,把ID做成non-clusteredPK会更好。对于检索少量行的查询,使用从 non-clustered PK 到复合聚集索引的嵌套循环连接应该没问题。但是在通过 (Fk1,Fk2) 进行查询时进行 300,000 次查找将非常昂贵。这些查询可能会进行 table 扫描,因为它非常昂贵。
并且在通过 (FK1,FK2,FK3) 对 table 进行聚类后,考虑通过 FK2 将其划分为 10-100 个单独的分区。那么像 WHERE Fk1 = 123456 AND FK2 = 654321
这样的谓词将只需要扫描包含 FK2=654321 的分区,并且可以在该分区中直接查找 FK1=123456 的第一页。
此外,如果 PAGEIOLATCH 等待是查询运行时的重要部分,请考虑 ROW 或 PAGE 压缩。