Java Mysql:在低基数列上执行count(*)操作的最佳方法

Java Mysql:在低基数列上执行count(*)操作的最佳方法,java,mysql,indexing,aggregate-functions,Java,Mysql,Indexing,Aggregate Functions,背景: 我有一个Mysql模式,其结构如下 @Data public class DBQueryEvaluation { //primary key private final Long id; //The combination of a 'query' and an 'evaluationId' will always be unique. private final Long evaluationId; private final String q

背景:

我有一个Mysql模式,其结构如下

@Data
public class DBQueryEvaluation {
    //primary key
    private final Long id;

    //The combination of a 'query' and an 'evaluationId' will always be unique.
    private final Long evaluationId;
    private final String query;

    private final Date createdAt;
    private final Date updatedAt;
}
约束

查询”和“评估ID”的组合将始终是唯一的

对于给定的evaluationId,可以有很多查询。表中总共有500万条记录。(每个evaluationId大约50000个查询,其中100个此类评估=500万条记录)

目标:

要对给定的evaluationId进行计数(记录)

问题:

鉴于evaluationId的基数非常低(相同的evaluationId重复了约50k条记录):

  • 索引“evaluationId”是这里推荐的做法吗。BTree实现应该能够提供以毫秒为单位的计数。(<10ms)
  • 为这样一个低基数属性编制索引可能有什么缺点(如果有的话)
  • 获得计数(*)的其他最佳方法是什么
  • ==更新===

    • 我期待一个完全一致的观点。没有近似值
    • 可以在现有行的顶部应用更新
  • 索引“evaluationId”是这里推荐的做法吗。BTree实现应该能够提供以毫秒为单位的计数。(<10ms)
  • 是的,如果没有索引,引擎必须执行完整的表扫描。但是,使用索引时,它不必访问数据记录,只需从索引中获取计数。为此,它需要读取比数据记录数量少得多的索引记录,因为:

    • 索引叶块具有多个记录指针,这些指针以块块的形式读取
    • 隔离与求值id相关的叶块所需的额外块读取数与块总数成对数关系
    例如,如果块大小为10,并且50000条记录具有评估id,则需要读取大约5555个块。将此与表扫描中需要读取的至少500000个块进行比较。显然,数据库有优化方法,这会使公平比较变得复杂,因此尝试一下是有意义的

  • 为这样一个低基数属性编制索引可能有什么缺点(如果有的话)
  • 基数的作用取决于一个块中适合多少数据记录(即。
  • 建议在此处对“evaluationId”进行索引。BTree实现应该能够提供毫秒级的计数。(<10ms)
  • 是的,如果没有索引,引擎必须执行完整的表扫描。但是,使用索引,它不必访问数据记录,但可以单独从索引中获取计数。为此,它需要读取远小于数据记录数的索引记录数,因为:

    • 索引叶块具有多个记录指针,这些指针以块块的形式读取
    • 隔离与求值id相关的叶块所需的额外块读取数与块总数成对数关系
    例如,如果块大小为10,50000条记录具有评估id,则需要读取约5555个块。将其与至少500000个需要在表扫描中读取的块进行比较。显然,数据库具有优化方法,这会使公平比较变得复杂,因此尝试一下是有意义的

  • 为这样一个低基数属性编制索引可能有什么缺点(如果有的话)

  • “基数”的作用取决于一个块中有多少数据记录(即一次写入数据),然后考虑一个数据仓库,比如@瑞克·詹姆斯:数据写得相当频繁。OOP,我的意思是“数据一旦被写入,就不会被修改”。NP..它可能被修改了一次。(我也期待一个完全一致的视图)将更新一次写入的数据吗?然后考虑一个数据仓库,比如@瑞克·詹姆斯:数据写得相当频繁。OOP,我的意思是“数据一旦被写入就不被修改”。NP..它可能被修改了一次。(我也期待一个完全一致的视图)。将更新PostThank@trincot。我正在寻找完全一致的视图。另外,如果您能解释一下您是如何到达5555的,将不胜感激。同样的应该是日志(基本2)根据我的理解是500000。”“例如,如果块大小为10,50000条记录具有评估id,则需要读取大约5555个块。”“我是如何到达5555的:日志基数是B-树块的算术数。我查看了金字塔(子树)B-树中具有具有搜索id的叶块的块数。该金字塔的底层将有5000个块,每个块有10个条目(=50000个记录指针)。父层的块数将减少10倍(500),祖父母级别将有50个区块,…等等。我忽略了到达这个金字塔所需的路径,因为它只包含两个以上的级别(=两个以上的读取)。一个“完全一致的视图”:你看到不一致了吗?谢谢。完全一致的视图我的意思是“没有近似值”(在回答您的评论“它是否真的是49756而不是49695”时)我很好奇这么严格的计数要求的商业价值是什么。主要是因为这些信息马上就过时了。但无论如何,我的建议是我的答案最后几段中的方法。根据我的经验,典型的算术是100。谢谢@trincot。我在寻找一个完全一致的观点。另外,如果你能明白你是如何到达5555的。根据我的理解,同样应该是log(基数2)500000。”“例如,如果块大小为10,50000条记录具有评估id,那么需要读取大约5555个块。”“我是如何到达5555的:log base是任意算术数的”