當前位置: 首頁>>係統&架構>>正文


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/zh-tw/article/3548.html,未經允許,請勿轉載。