如何在一个数据库表上计算简单选择查询的开销?

时间:2016-03-18 22:03:11

标签: mysql query-optimization cost-based-optimizer

员工(ename,title,dname,address) 所有都是相同长度的字符串字段。

ename属性是候选键。 该关系包含10,000页。 有10个缓冲页面。

查询是: SELECT E.title,E.ename 来自员工E. WHERE E.title ='管理员'

假设只有10%的Employee元组符合选择条件。

假设ename上的聚簇B +树索引是(唯一的索引)可用。最佳计划的成本是多少?

我如何计算这笔费用?如果标题上有一个聚类B +树索引,我该如何计算?

另一个问题: 选择E.ename 来自员工E. WHERE E.title ='管理员' AND E.dname ='财务'

假设只有10%的员工元组符合条件E.title ='Administrator',只有10%符合E.dname ='Finance',只有5%满足这两个条件。

假设群集B +树索引是(唯一的索引)可用。最佳计划的成本是多少?

专家!请帮忙。任何意见/建议将不胜感激。我想了解整个过程。我做了很多研究,我想我知道如何计算每个操作的成本,让我感到困惑的是他们说这个关系包含10,000页而不是说每个页面中有多少元组?从我学到的东西,我相信我们必须有关于元组的关系的总大小,我是否正确?为什么呢?

感谢任何花时间阅读问题的人: - )

1 个答案:

答案 0 :(得分:1)

如果没有合适的索引,查询将执行表扫描。由于读取行是执行时间的主要部分(在许多情况下);你提到的变化并不重要。

如果你有一个相关的索引,那个索引足够有选择性(10%可能足够“有选择性”),那么查询将有两个步骤:

  1. 扫描索引的部分,这是一个单独的BTree。
  2. 对于每一行,从该BTree获取PRIMARY KEY(假设您使用的是InnoDB)。使用该PK,在主BTree中查找包含PK和数据的行。
  3. 如果所有必要的块都缓存在buffer_pool中(同样,假设InnoDB),成本的变化相当小。

    如果并非所有块都在缓存中(因为mysqld刚刚启动,或者因为索引/数据太大而无法保持缓存),那么您将“计算磁盘命中率”。这是因为“成本”的主要部分是I / O.现在计算成本非常复杂,因为需要知道已经缓存了多少百分比,查询是否会“破坏”缓存,10%是均匀分散,还是聚集在一起,或者介于两者之间。

    由于(对于InnoDB),PK与数据“聚集”,因此PK的查找与通过辅助键的查找不同。

    10K行是“小”。 10个缓冲页面 - 你的意思是什么? “所有都是相同长度的字符串字段” - 使用CHAR代替VARCHAR是不现实的,不是一个好主意。无论如何,字符串长度对这个讨论几乎没有影响。

    WHERE E.title=‘Administrator’ AND E.dname=‘Finance’ - 以 顺序为INDEX(title, dname)提出要求。

    “经验法则”:一个块(InnoDB)可以容纳100行(数据或索引)。 (当然,这可能会有很大差异。但有时候“计算磁盘命中率”很方便。)

    在我的cookbook中,我发现更容易专注于设计“最佳”索引,而无需计算“成本”。

    有关查询的进一步说明

    “假设只有10%的员工元组符合条件E.title ='管理员',只有10%符合E.dname ='财务',只有5%满足这两个条件。”对于MySQL,这里有更多细节:

    案例1:INDEX(title) - 类似于第一个查询 - 索引范围扫描为10%,然后探测数据。
    案例2:INDEX(dname) - 同上。
    情况3:两个索引 - 有一个 slim 机会使用“索引合并交叉”来做两个索引“范围扫描”,将两个集合在一起,然后到达行的数据。
    案例4(最好):INDEX(title, dname)(或相反的顺序):返回索引范围扫描,但仅限于5%的项目。

    MySQL的首选引擎是InnoDB。我所讨论的是假设,而不是MyISAM。使用InnoDB,“数据”存储在B +树中,每个二级索引也是如此。在考虑如何执行查询时,请记住这种相似性。另请注意,辅助索引的“叶节点”包含PK,从而提供了查找记录其余部分的机制。