在低选择性色谱柱上选择记录的策略有哪些?
一个示例可能是订单表,多年来,您构建了大量已完成的订单,但通常需要选择活动订单。订单可能会经历生命周期,例如放置,库存分配,从仓库中挑选,发送给客户,开具发票和付款。订单可能会被取消,保留等等。大多数记录最终将处于最终状态(例如付费),但您可能经常需要选择分配的订单。在这种情况下,顺序读取会很慢。
关于索引的类似问题
MySQL: low cardinality/selectivity columns = how to index?
Do indexes suck in SQL?
What are indexes and how can I use them to optimize queries in my database?
Defining indexes: Which Columns, and Performance Impact?
和许多其他人相关的减少。
我读过的方法(在stackoverflow和其他地方)包括
create index x on t(c2) where c1='a'
)active_customers(customer_id)
我目前的DBMS不支持上面列出的前三个选项,其余的似乎有问题 - 还有其他常用的方法吗?
更新:我见过 - 索引低选择性列,但只选择高选择性值。
答案 0 :(得分:3)
在您列出的所有方法中,只有一种(使用顺序读取)是与低选择性有关的方法(好的,群集也可以限定)。
如果您对列的选择性较低,则意味着扫描的性能优于查找。
索引可以用来做
否则它不是很有用。
如果选择性低,则意味着将读取大部分索引,如果使用查找,则将以某种随机顺序读取大部分数据。如果覆盖基础表的很大一部分,这是低效的,因此更好的方法是执行顺序读取(这也很慢)。
因此,如果选择性很低,那么你无能为力(聚类可以提供帮助)。
然而,我不相信您明白在您的示例中不选择性较低。正如你所说,大多数参赛作品都会被支付,而且会分配很少的参赛作品。这些(已分配)条目将具有高选择性。特别是如果存在其他条件且,则存在包含这些附加条件的复合索引。
所以,你可能会碰到一个没问题的人。
现在,您可以通过分区数据或使用补充表(如果需要)来进一步提高性能。
答案 1 :(得分:3)
我同意Unreason的但分支。但是有一些事情需要了解这个案例。
这称为歪斜和歪斜杀戮。这是部分索引的完美用途,您可以排除95%的付费发票,并仅索引更有趣和有选择性的统计数据。但你没有那个。您可以将所有行水平分区为单独的表/分区,但是您需要考虑行迁移(从一个状态移动到另一个状态)并且这很昂贵。 DBMS必须执行更新,删除和插入以更改状态。如果你是一个会伤害的高容量系统。
忘记关于是否根据选择性进行索引的说法,因为在快速变化的列上放置索引通常也是一个坏主意。你的索引将有热块,其中所有的步骤1都被移除,而另一个步骤2的所有步骤都被插入,哦顺便说一下,某些步骤2同时被移除到步骤3中。这不会很好地扩展。
我建议将状态垂直分区为单独的表格。
您的发票表将包含PK以及除状态以外的所有列。
您的状态可以通过两种方式处理。该表将PK值作为FK返回到发票表,状态和您输入该状态时的时间戳。最好的是状态上的水平分区表。您将为每种状态分配一个分区。因此,找到所有或一个“已放置”状态将分区修剪并只读取它所需的分区 - 这是一个非常少的块。由于行非常狭窄,因此您可能会在一个块上获得400个发票状态。查看任何一张发票的状态很容易,因为PK上有一个全局索引。
如果您的RDBMS不支持使用行迁移进行分区,则需要将这些分区作为表进行管理,然后从一个分区中删除并插入另一个分区。您将这些移动封装在过程中的事务中,因此您可以保持数据清洁。每张发票都在一个且只有一个状态表中。更难的部分是按发票ID查询,您必须检查每张表以查看它的位置。
您还有其他选择 您可以编写付费状态。如果它是分区表,则只需在发票状态表中移至付款时即可将其删除。 (当然,您会将付费记录写入奖励材料中提到的历史记录表)。然后你将对状态表进行外连接,并且null表示已付费。如果您几乎从不查询付费状态,那么实际上没有理由进行快速查询。
在任何一种情况下,您都希望在报告表中跟踪这些变动。每次更新状态时,您都希望将其写入历史记录表。最终你会想要分析我称之为运输时间的东西。按月填写到付费的平均时间是多少?由于经济不景气,这种情况会增加吗?从月到月的运输时间是多少。由于度假时身体缺失,夏季月份需要更长时间吗?你明白了。通过更新该列,您将丢失这些答案,因此您需要将该历史记录日志嵌入到您的过程中。
答案 2 :(得分:1)
分区是一种将相同的表存储在基于数据的不同区域中的方法 - SQL开发人员不必访问单独的表。
我认为这是所描述问题的理想选择 - 您可以在此处找到有关Informix的更多信息:http://www.dbmag.intelligententerprise.com/blog/main/archives/2008/09/data_partitioni.html
答案 3 :(得分:1)
如果您可以放松数据库规范化,并且可能的状态数量很少(例如:<5),则可以为每个状态添加一个可空列,并将索引放在这些列上。许多引擎(例如MongoDB)将跳过具有空值的行,而仅对具有实际数据的行建立索引(稀疏索引)。例如:
Invoice# Date State IsPlaced IsPaid IsFulfilled
1 Apr-20 Fulfilled (null) (null) yes
2 Apr-20 Fulfilled (null) (null) yes
3 Apr-20 Fulfilled (null) (null) yes
4 Apr-21 Fulfilled (null) (null) yes
5 Apr-21 Fulfilled (null) (null) yes
6 Apr-21 Paid (null) yes (null)
7 Apr-21 Placed yes (null) (null)
8 Apr-22 Placed yes (null) (null)
9 Apr-22 Paid (null) yes (null)
10 Apr-22 Placed yes (null) (null)
您可以在单独的表中获取此信息,并且可能由触发器驱动,或者至少在约束条件下进行检查。
这不是通用解决方案,实际上可伸缩性较差,但是将允许您在更合理的列(例如发票日期)上使用分区。
这种技巧通常用于数据仓库设计中,在这种设计中,处理大型数据集的效率比数据规范化更为重要。