当前位置: 首页>>系统&架构>>正文


MariaDB创建降序索引

自从诞生以来,MariaDb(MySQL)索引有一个限制:它们不能降序(create index desc)。是的,ALTER TABLE和CREATE INDEX可以包含ASC和DESC关键字,这在MySQL中完全合法,但这并不意味着下降索引被创建。也就是Mysql支持索引desc这样的语法,但是实际上并不支持这样的功能,比如:order by column _name desc并不能使用索引。这是一个众所周知的MySQL功能:当它不能做某事时,它只是假装。嗯…有人认为这是一个功能,但我认为这是一个BUG(一个错误是一个意想不到的行为),那我们能做什么呢?

mariadb

缺少对降序索引的支持只是一个问题,当我们需要创建一个索引,其中至少有一列升序,并且至少有一列是降序。例如,MySQL假装理解以下语句,但是生成的索引不太可能有助于我们:

CREATE INDEX my_index ON my_table (my_column ASC, your_column DESC);

ORDER BY my_column ASC,your_column DESC将无法使用此索引。

MariaDB有一个功能,为缺少降序索引提供了一个很好的解决方法:PERSISTENT列。如果您不了解它们,请先查看MariaDB KnowledgeBase

PERSISTENT列如何帮助我们创建混合order索引?如果你还没有猜到,我会告诉你的。假设我们有一列A,我们希望它成为ASC + DESC索引的一部分。我们需要创建一个PERSISTENT列rev_A,其值是根据A中的值计算的。这里重要的是rev_A值的顺序与A是相反的。这是一个例子:

CREATE TABLE `exam_scores`
(
      `id` INT SIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
    , `student_name` VARCHAR(200) NOT NULL
    , `exam_code` CHAR(1)
    , `exam_score` SMALLINT UNSIGNED NOT NULL
    , `exam_date` DATETIME NOT NULL

    -- auxiliary columns
    , `rev_exam_code` TINYINT UNSIGNED AS (255 - ORD(exam_code)) PERSISTENT
    , `rev_exam_score` SMALLINT SIGNED AS (0 - exam_score) PERSISTENT
    , `rev_exam_date` SMALLINT UNSIGNED AS (DATEDIFF('2050-01-01', exam_date)) PERSISTENT

    -- mixed indexes
    , INDEX `desc_exam_code` (`rev_exam_code`, `student_name`, `exam_code`)
    , INDEX `desc_exam_score` (`rev_exam_score`, `student_name`)
    , INDEX `desc_exam_date` (`rev_exam_date`, `student_name`, `exam_date`)
)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = 'utf8'
;
-- this is needed because some rev* columns return negative values
SET @@global.sql_mode := CONCAT(@@global.sql_mode, ',NO_UNSIGNED_SUBTRACTION');
SET @@session.sql_mode := @@global.sql_mode;
INSERT INTO `exam_scores`
        (`student_name`, `exam_code`, `exam_score`, `exam_date`)
    VALUES
          ('Anthony Stark', 'F', 100, '1994-01-01')
        , ('Klark Kent', 'G', 60, '2000-01-01')
        , ('Corto Maltese', 'A', 50, '2007-01-01')
        , ('Tin Tin', 'Z', 900, '2005-01-01')
        , ('Philip Mortimer', 'C', 20, '2000-01-01')
        , ('Dago', 'M', 80, '2004-01-01')
    ;

是的,这张表设计得很烂。你想说它不是好的关系表等等,但是我们在谈论在MariaDB中的混合order索引,而不是关系理论。

现在很清楚吗?但愿如此。我们来看一个示例查询。我们想列出学生:最近的考试,如果两个日期相同,按字母排序。

MariaDB [test]> EXPLAIN SELECT `student_name`, `exam_date`
    -> FROM `exam_scores`
    -> ORDER BY `rev_exam_date` ASC, `student_name` ASC;
+------+-------------+-------------+-------+---------------+----------------+---------+------+------+-------------+
| id   | select_type | table       | type  | possible_keys | key            | key_len | ref  | rows | Extra       |
+------+-------------+-------------+-------+---------------+----------------+---------+------+------+-------------+
|    1 | SIMPLE      | exam_scores | index | NULL          | desc_exam_date | 613     | NULL |    7 | Using index |
+------+-------------+-------------+-------+---------------+----------------+---------+------+------+-------------+
1 row in set (0.00 sec)

desc_exam_score索引表明:在索引中包含原始列并不是必须的:

MariaDB [test]> EXPLAIN SELECT `student_name`, -`rev_exam_score` FROM `exam_scores` ORDER BY `rev_exam_score` ASC, `student_name` ASC;
+------+-------------+-------------+-------+---------------+-----------------+---------+------+------+-------------+
| id   | select_type | table       | type  | possible_keys | key             | key_len | ref  | rows | Extra       |
+------+-------------+-------------+-------+---------------+-----------------+---------+------+------+-------------+
|    1 | SIMPLE      | exam_scores | index | NULL          | desc_exam_score | 605     | NULL |    6 | Using index |
+------+-------------+-------------+-------+---------------+-----------------+---------+------+------+-------------+
1 row in set (0.00 sec)

-column_name显然是一个快速的获得真实值的操作。

示例表格显示了如何为数字,日期和ASCII 1字符串创建一个反向的索引部分。多字符ASCII字符串也很简单。我不知道如何创建一个反转的Unicode列。如果找到方法,请在文章下面留下评论。

本文翻译自:https://falseisnotnull.wordpress.com/2014/04/25/descending-indexes-in-mariadb/

本文由《纯净天空》出品。文章地址: https://vimsky.com/article/3548.html,未经允许,请勿转载。