我有一个像这样的表,用于存储所运行的各种程序的配置。看起来像这样:
+--------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------+------+-----+---------+-------+
| Date | date | YES | MUL | NULL | |
| Program | varchar(20) | YES | MUL | NULL | |
| ConfigFile | int(11) | YES | | NULL | |
| Parameter | varchar(20) | YES | | NULL | |
| Value | varchar(20) | YES | | NULL | |
+--------------+---------------+------+-----+---------+-------+
ConfigFile
字段包含配置文件的编号-对于某些程序,可以选择多个配置文件。
它具有几个索引,如下所示:
+-------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| lists | 1 | Date | 1 | Date | A | 1108060 | NULL | NULL | YES | BTREE | | |
| lists | 1 | Date | 2 | Program | A | 1108060 | NULL | NULL | YES | BTREE | | |
| lists | 1 | Date | 3 | Parameter | A | 1108060 | NULL | NULL | YES | BTREE | | |
| lists | 1 | Program | 1 | Program | A | 4676 | NULL | NULL | YES | BTREE | | |
| lists | 1 | Program | 2 | Parameter | A | 183706 | NULL | NULL | YES | BTREE | | |
+-------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
现在让我们说我想知道给定程序的参数是什么。看来我应该可以执行以下操作:
SELECT DISTINCT Parameter FROM params WHERE Program = 'MyProgram';
这具有以下说明计划:
+----+-------------+--------+------------+------+----------------+---------+---------+-------+-----------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+----------------+---------+---------+-------+-----------+----------+--------------------------+
| 1 | SIMPLE | params | NULL | ref | Date,Program | Program | 23 | const | 137203382 | 100.00 | Using where; Using index |
+----+-------------+--------+------------+------+----------------+---------+---------+-------+-----------+----------+--------------------------+
Program
有15种不同的选择,每个程序的Parameter
可能有10到100个值。
了解数据库索引的工作原理后,我希望它可以立即完成。特别是,我希望基础数据结构是一个具有15个节点的二进制搜索树,我将搜索这些树以找到与我的程序相对应的树。找到程序后,它带我到第二个二叉搜索树,该树可能有100个或更少的节点,然后我只需遍历。
不过,当我实际上运行查询时,它花了几分钟时间。
对我来说,这表明二进制搜索树中可能存在相同值的多个副本,表的每个节点一个。这是正在发生的事情吗,如果是这样,我该怎么做以减轻这种情况?
我考虑过使用一个具有唯一三元组(日期,程序,参数)的表并具有关系,但是我不确定在这种情况下如何执行数据的批量插入。而且,如果我错了为什么这么慢,那当然也帮不上忙。
答案 0 :(得分:1)
InnoDB的B + Tree二级索引不会以这种方式形成。这样想吧:
Program
,Parameter
,PK
组成的字符串。注意:没有暗示被Program
分割。如果99.9%的程序属于程序5,该怎么办?那将是一个相当不平衡的BTree。对于一个罕见的查询很方便,但是对于大多数其他查询却比较慢。
使用平衡良好的B +树,您的查询必须:
Program = 'MyProgram'
的第一个“行” Parameter
。Program = 'MyProgram'
失败时退出。注意:
DISTINCT
。Program
和Parameter
(而这些是INDEX
中的列)。 PK也隐式地可用于“覆盖”。我考虑过一张带有唯一三元组(日期,程序,参数)的表
是的,拥有这样一个表将使您的查询运行更快。但这值得维护吗?
该表允许您执行的另一件事是将这3列标准化为单个MEDIUMINT UNSIGNED
(仅3个字节),而不是现在平均行上可能使用了30个字节。同样,JOINs
等的复杂性是否会超过收益?它将使磁盘占用空间减少约50%。