假设我在每个查询中都正确地查询分区键。有没有合理的理由将分区键放在第一行以外的任何位置
我觉得我对这个指数的运作方式有些不了解。假设MySQL和InnoDB。
我想我明白了,通常情况下,你会把最有选择性的钥匙放在第一位,然后把不太有选择性的放在第二位。分区键通常是选择较少的键之一。但是,如果每个查询中都包含分区键,那么首先包含分区键有什么区别?这在其他方面也有帮助吗?例如,如果分区键在主键索引的前面,我就不必在每个索引中都包含它:使用其他索引的查询可以从主键索引中借用主键,这与最左边的键约束一致。
我不知道一个索引本身是否被分区,但如果它是一个覆盖索引,它似乎可以被分区。(我说得对吗?(如果是这样,分区键必须是第一个,否,分区才能工作?
例如:
CREATE TABLE `fee` (
`fi` INT ,
`fo` INT ,
PRIMARY KEY ( `fi` , `fo` ) ,
) ENGINE = INNODB
PARTITION BY RANGE ( `fi` ) (
. . .
);
或者。
CREATE TABLE `fee` (
`fi` INT ,
`fo` INT ,
PRIMARY KEY ( `fo` , `fi` ) ,
) ENGINE = INNODB
PARTITION BY RANGE ( `fi` ) (
. . .
);
哪一个,如果有,本质上更好,为什么或为什么不?
谢谢你抽出时间。
这两列的选择性并不像一些人想象的那么重要。
如果您将表格查询为:
SELECT ... FROM fee WHERE fi=? AND fo=?
那么,它是按fi,fo
还是按fo,fi
搜索B树又有什么关系呢?它最终会找到相同的记录,并且需要大致相同数量的步骤才能做到这一点。理论上存在差异,但在大多数情况下不会产生显著差异。
更重要的是,如果查询只搜索主键的一列或另一列。
您提到所有查询都在分区列上搜索,在本例中为fi
。您是否有在fi
上搜索但不在fo
上搜索的查询?
SELECT ... FROM fee WHERE fi=?
如果fi
是主键的第一列,这将进行分区修剪,并且还使用primary key索引,因为搜索词位于第一列。
mysql> explain partitions select * from fee where fi = 175;
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | fee | p2 | ref | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
而如果fi
是主键的第二列,那么它可以进行分区修剪,但不使用索引。
mysql> explain partitions select * from fee where fi = 175;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | fee | p2 | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
索引也被分区。将分区视为一系列完全独立的表,具有相同的列和索引,只是行的子集。一旦查询确定了要读取哪个分区,它就按照对未分区表执行查询的方式执行查询,根据查询条件选择索引。它会使用主键进行搜索吗?
mysql> explain partitions select * from fee where fi = 175 and created_at < now();
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | fee | p2 | range | created_at | created_at | 6 | NULL | 1 | 100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------+
在这里,我们看到fi
上的条件导致了分区修剪,但优化器更喜欢created_at
上的索引。它在相应的分区中搜索该索引。
"你把最有选择性的键放在第一位,把不太有选择性的放在后面"——不,那是老太太的故事。
将使用"="测试的键放在第一位是一个简单而重要的规则。
将复合InnoDB BTree索引想象成这样工作。将所有列连接在一起,然后将BTree想象为具有单个字符串作为键。
将";分区键";索引中的第一个是最不有用的地方!你已经在修剪了;把它放在索引中实际上是多余的。但是,对于任何Unique键(包括"PRIMARY key"(,都是必需的。
是的,您正确地观察到PK列隐含地包含在每个辅助密钥中,因此分区密钥也包含在内。
请注意,如果分区键实际上不是所需UNIQUE
键的一部分,那么唯一性约束是不可能的(在MySQL中(。然而,附加PK不是唯一性约束的一部分。由于MySQL只愿意检查一个分区的唯一性,因此必须包含分区密钥,以提供状态为"的语义;独特的";整个桌子。(是的,这有点复杂;接受它吧。(
在您的示例中,如果执行SELECT .. WHERE fi BETWEEN 1 and 2
AND fo=3,则以fi
开始的任何索引(PK是一个索引(都将比fo
在索引中第一个更难工作。
因此,经验法则是将分区键移动到包含它的任何索引的端。(我只看到过一个罕见的异常;我忘记了细节。(