【问题标题】:Best way to use compound Index to query with multiple combination of query parameters?使用复合索引查询多个查询参数组合的最佳方法?
【发布时间】:2017-04-19 19:35:32
【问题描述】:

我正在构建一个功能来估计我的广告服务平台的库存。我试图用它们的基数来估计的字段如下:

字段:基数

位置:10000(班加罗尔、钦奈等)

n/w 速度 : 6 (w, 4G, 3G, 2G, G, NA)

价格范围:10(1、2、3、4、5、6、7、8、9、10)

users:包含属于上述任何组合的用户数。

例如。 {'location':'bengaluru', 'n/w':'4G', priceRange:8, users: 1000}

表示 1000 个用户来自班加罗尔,拥有 4G 和 priceRange = 8

所以总组合可以是 10000 * 6 * 10 = 600000 并且将来可以在 29 左右添加更多字段(目前是 3 个位置,n/w,价格范围),总组合可以达到 1000 万的数量级。现在我想估计有多少用户属于

现在我需要的查询如下: 1) 查找来自 location:bengaluru , n/w:3G, priceRange: 6 的所有用户

2) 查找来自班加罗尔的所有用户

3) 查找所有低于 n/w: 3G 和 priceRange: 8 的用户

解决此问题的最佳方法是什么?

哪个数据库最适合这个要求。我需要建立什么索引。复合指数会有帮助吗?如果是,那么如何?任何帮助表示赞赏。

【问题讨论】:

  • 虽然我同意此时的组合为 600,000,但我相信您的记录数将为 1000*fields 或 29000(如果 29 个字段)。由于每个用户对这些属性中的每一个都只有一个值,对吗?所以你可以有一个 userFields 表,它简单地定义表用户和相关字段的值..
  • 1000 是属于该存储桶的用户数。我相信这个问题目前还不清楚。考虑到您的方法,您将如何找到来自班加罗尔且 priceRange 为 7 的用户数量?
  • 可能是我没有清楚地理解您的解决方案。考虑您的方法 您将如何找到来自 bengaluru 且 priceRange 为 7 的用户数量?让我们举个例子来解释一下这个问题:很少有文件存在 {'location':'bengaluru', 'n/w':'4G', priceRange:8, users: 1000}, {'location': 'bengaluru', 'n/w':'4G', priceRange:7, users: 10}, {'location':'chennai', 'n/w':'4G', priceRange:8, users: 100}所以对于像 find all users from bengaluru 这样的查询将是 1010,拥有 4G 的用户是 1110,priceRange 为 8 的用户是 1100
  • Select Count(1) from TableUservalues where (field,value) in (('location','bengaluru'),('priceRange',7)) having count(distinct concat(field,value))=2 这是上一个问题中的一个示例:stackoverflow.com/questions/927724/… 这里唯一的区别是您有一个成对的值映射,因为它们只有一个键和一个值。
  • 其他可能的示例:stackoverflow.com/questions/24179584/… ... stackoverflow.com/questions/16803592/… 以及有关此方法的优缺点的更多信息:stackoverflow.com/questions/126271/…

标签: database inventory-management nosql


【解决方案1】:

这是我的最终答案:

Create table Attribute(
  ID int,
  Name varchar(50));

Create table AttributeValue(
 ID int,
 AttributeID int,
 Value varchar(50));

Create table userAttributeValue(
  userID int,
  AttributeID varchar(20),
  AttributeValue varchar(50));

Create table User(
  ID int);

Insert into user (ID) values (1),(2),(3),(4),(5);

Insert into Attribute (ID,Name) Values (1,'Location'),(2,'nwSpeed'),(3,'PriceRange');
Insert into AttributeValue values 
  (1,1,'bengaluru'),(2,1,'chennai'),
  (3,2, 'w'), (4, 2,'4G'), (5,2,'3G'), (6,2,'2G'), (7,2,'G'), (8,2,'NA'),
  (9,3,'1'), (10,3,'2'), (11,3,'3'), (12,3,'4'), (13,3,'5'), (14,3,'6'), (15,3,'7'), (16,3,'8'), (17,3,'9'), (18,3,'10');

Insert into UserAttributeValue (userID, AttributeID, AttributeValue) values
(1,1,1),
(1,2,5),
(1,3,9),
(2,1,1),
(2,2,4),
(3,2,6),
(2,3,13),
(4,1,1),
(4,2,4),
(4,3,13),
(5,1,1),
(5,2,5),
(5,3,13);

Select USERID
from UserAttributeValue
where (AttributeID,AttributeValue) in ((1,1),(2,4)) 
GROUP BY USERID
having count(distinct concat(AttributeID,AttributeValue))=2

现在,如果您需要一个计数包装 userID 并除以传入的属性,因为每个用户每个属性将有 1 条记录,并且要获得“用户计数”,您需要除以属性数。

  1. 如果 UI 设计正确,这允许 N 个属性和每个用户的 AttributeValues 增长,而无需更改 UI 或数据库。
  2. 通过将每个数据点视为一个属性并将它们存储在一个位置,我们可以强制执行数据库完整性。
  3. 属性和属性值表成为用户属性值的查找,因此您可以将 ID 转换回属性名称和值。
  4. 这也意味着我们只有 4 个表 user、attribute、attributeValue 和 UserAttributeValue。
  5. 从技术上讲,您不必在 userAttributeValue 上存储 attributeID,但出于以后加入/报告的性能原因,我认为您会发现它很有用。
  6. 您需要向表中添加适当的主键、外键和索引。它们应该是不言自明的。在 UserAttributeValue 上,我将有几个复合索引,每个索引都有不同的唯一键顺序。仅取决于您将要执行的报告/分析的类型,但在需要性能调整时添加键是司空见惯的。

假设:

  1. 在所有情况下,所有数据值都是 varchar 数据,您可以接受。
  2. 如果需要,您可以在属性表上添加数据类型、精度和比例,并允许 UI 根据需要转换属性值。但由于它们都在数据库中的同一个字段中,它们都必须是相同的数据类型。并且具有相同的精度/比例。
  3. 可能需要数据透视表来显示数据,并且您知道如何处理这些(引擎支持它们!)

不得不说我喜欢金属运动;但仍然会感谢其他人对 SO 的反馈。我已经在我开发的 1 个系统中使用了这种方法,并且在我支持的两个系统中都使用了这种方法。存在一些挑战,但它确实遵循第 3 范式数据库设计(除了 userAttributevalue 中的复制属性 ID,但这是为了提高报告/过滤的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 2019-11-22
    • 2013-05-11
    • 2021-09-27
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多