不使用索引:创建数据表时不增加索引,而是使用分区定位到所需要的数据行。只要你使用 WHERE 条件将查询切分到很小的分区范围,就已经足够了。这个时候需要通过数学方法计算查询的响应时间是否能够接受。当然,这里的假设是不会将数据放到内存中,而是全部数据都从磁盘读取。因此数据很快就会被其他查询覆盖,使用缓存没什么意义。这种情况一般用于大量数据表的基数是常规的。需要注意的是,需要限制分区数在几百。
NULL 空值可能导致分区过滤失效:当分区函数可能是 NULL 时,分区工作的结果就会很奇特。它会假设第一个分区是特殊的。假设使用 PARTITION BY RANGE YEAR(order_date)这样的分区方法,如果 order_date 这个列是 NULL 或者无效的日期都会存储在第一个分区。假设写了一个查询使用了这样的查询条件 :WHERE order_date BETWEEN '2021-01-01' AND '2021-01-31'。MySQL 实际上会检查2个分区,一个是 YEAR 这个函数 在接收到无效输入时可能会返回 NULL,另一个是符合条件的值可能是 NULL(存储在第一个分区中)。这种情况对其他函数也可能,例如 TO_DAYS。如果第一个分区很大的话,就会产生问题,尤其是使用第一种不使用索引策略时。从两个分区查找数据而不是一个分区的效果是完全意外的。为了避免这种情况,应该创造“假的”第一分区,例如 PARTITION p_nulls VALUES LESS THAN (0)。如果没有无效数据存入数据表的话,这个第一分区将是空的,即便它也会被扫描,但是因为是空的或者数据量很少,对性能影响不大。这种情况在 MySQL 5.5以后,如果直接使用列进行分区的话就不需要处理,但是如果是使用函数的话就要这样做。
索引与分区不匹配:假设定义了一个索引与分区条件不匹配,查询就可能无法对分区进行过滤。假设定义了 字段 a 的索引却使用 字段 b 进行分区。由于每个分区都会有自己的索引,针对这个索引的查询会遍历所有分区的索引树。如果索引树的非叶子节点都常驻内存查询起来还比较快,但是也没法避免全部索引的扫描。为了避免这种情况,应当尽量避免使用非分区的索引列,除非WHERE 条件本身能够指定分区。看起来这样很容易避免,实际上却令人吃惊。例如,假设一个分区表用在第二个表查询联合查询后,而联合查询使用的索引并不是分区的索引。则联合查询的每一行都会访问和扫码第二张表的分区。
打开和锁定分区代价也可能很高:分区表带来的一个负面效应是查询时需要对每个分区进行打开和锁定。而这个过程是在过滤分区前进行的。这个代价与分区类型无关,且会影响所有的操作语句。这种影响对于短数据量的查询尤其明显,例如只查询一行数据时。这种缺陷可以通过批量操作替代单次来降低,例如一次插入多行,或 LOAD DATA INFILE,一次按范围删除数据等等。当然,限制分区的数量也是有效的。
维护操作代价可能很高:有些分区的维护是很快的,例如创建或者删除分区。而其他操作,例如调整分区,就有点像 ALTER 对表的操作那样了:需要循环复制数据行。例如,调整分区会创建一个临时分区,然后将数据移入到新的分区,再删除旧的分区。