Indexing for keyset pagination in mysql

北慕城南 提交于 2019-12-23 04:38:28

问题


I am trying to build an index in mysql to support a keyset pagination query. My query looks like this:

SELECT * FROM invoice 
  WHERE company_id = 'someguid' 
    AND id > 'lastguidfromlastpage' 
  ORDER BY id
  LIMIT 10

Common knowledge on this says an index on company_id would contain the PRIMARY KEY of the table (id). Because of this I would expect to be able to use rows directly from the index without any need for the query to sort results first however my explain plan shows a filesort and an index merge:

mysql> explain SELECT *
-> FROM invoice
-> WHERE company_id = '37687714-2e9d-4daa-aee6-f7d56962f903'
->   AND id > '525ae038-0cc3-4f9a-85e6-6f36d43fae40'
-> ORDER BY id
-> LIMIT 10;
+----+-------------+---------+------------+-------------+-----------------------------+-----------------------------+---------+------+------+----------+---------------------------------------------------------------------------+
| id | select_type | table   | partitions | type        | possible_keys               | key                         | key_len | ref  | rows | filtered | Extra                                                                     |
+----+-------------+---------+------------+-------------+-----------------------------+-----------------------------+---------+------+------+----------+---------------------------------------------------------------------------+
|  1 | SIMPLE      | invoice | NULL       | index_merge | PRIMARY,invoice__company_id | invoice__company_id,PRIMARY | 76,38   | NULL |   48 |   100.00 | Using intersect(invoice__company_id,PRIMARY); Using where; Using filesort |
+----+-------------+---------+------------+-------------+-----------------------------+-----------------------------+---------+------+------+----------+---------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

If I explicitly add the id to the index then I get the explain plan I would expect:

mysql> explain SELECT *
    -> FROM invoice
    -> WHERE company_id = '37687714-2e9d-4daa-aee6-f7d56962f903'
    ->   AND id > '525ae038-0cc3-4f9a-85e6-6f36d43fae40'
    -> ORDER BY id
    -> LIMIT 10;
+----+-------------+---------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+-----------------------+
| id | select_type | table   | partitions | type  | possible_keys                  | key                            | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | invoice | NULL       | range | PRIMARY,invoice__company_id_id | invoice__company_id_id,PRIMARY | 76      | NULL |   98 |   100.00 | Using index condition |
+----+-------------+---------+------------+-------+--------------------------------+--------------------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

SHOW CREATE TABLE:

CREATE TABLE `invoice` (
  `id` varchar(36) NOT NULL,
  `company_id` varchar(36) NOT NULL DEFAULT '0',
  `invoice_number` varchar(36) NOT NULL DEFAULT '0',
  `identifier` varchar(255) NOT NULL,
  `created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `created_by` varchar(36) DEFAULT NULL,
  `data_source` varchar(36) NOT NULL,
  `type` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `invoice__company_id_id` (`company_id`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

select @@optimizer_switch;

use_index_extensions=on

MySQL version:

  • version: 5.7.26-29-57-log
  • innodb_version: 5.7.26-29
  • version_comment: Percona XtraDB Cluster (GPL), Release rel29, Revision 03540a3, WSREP version 31.37, wsrep_31.37

SHOW VARIABLES LIKE 'char%';

character_set_client    utf8
character_set_connection    utf8
character_set_database  latin1
character_set_filesystem    binary
character_set_results   utf8
character_set_server    latin1
character_set_system    utf8
character_sets_dir  /usr/share/mysql/charsets/

There are a few sources explaining that the company_id index on it's own should be sufficient for this:

  • https://stackoverflow.com/a/30152513/64023
  • https://dba.stackexchange.com/a/136029/166838

I've been unable to find official documentation about exactly what to expect. Is this related to the datatypes for the id? Is the common knowledge about mysql+innodb behavior incorrect?


回答1:


A guess...

ENGINE=InnoDB DEFAULT CHARSET=latin1

versus

character_set_client    utf8
character_set_connection    utf8
character_set_results   utf8

I would hope that it would convert the charset without fuss for

 WHERE company_id = '37687714-2e9d-4daa-aee6-f7d56962f903'
   AND id > '525ae038-0cc3-4f9a-85e6-6f36d43fae40'

Please provide this; maybe it will give a clue:

EXPLAIN FORMAT=JSON SELECT ...


来源:https://stackoverflow.com/questions/57223858/indexing-for-keyset-pagination-in-mysql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!