mysql - Index IN and a range -
i need find best index query:
select c.id id, type content c use index (type_proc_last_cat) left join battles b on c.id = b.id type = 1 , processing_status = 1 , category in (13, 19) , status = 4 order last_change desc limit 100";
the tables this:
mysql> describe content; +-------------------+---------------------+------+-----+---------+-------+ | field | type | null | key | default | | +-------------------+---------------------+------+-----+---------+-------+ | id | bigint(20) unsigned | no | pri | null | | | type | tinyint(3) unsigned | no | mul | null | | | category | bigint(20) unsigned | no | | null | | | processing_status | tinyint(3) unsigned | no | | null | | | last_change | int(10) unsigned | no | | null | | +-------------------+---------------------+------+-----+---------+-------+ mysql> show indexes content; +---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ | table | non_unique | key_name | seq_in_index | column_name | collation | cardinality | sub_part | packed | null | index_type | comment | +---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ | content | 0 | primary | 1 | id | | 4115 | null | null | | btree | | | content | 1 | type_proc_last_cat | 1 | type | | 4 | null | null | | btree | | | content | 1 | type_proc_last_cat | 2 | processing_status | | 20 | null | null | | btree | | | content | 1 | type_proc_last_cat | 3 | last_change | | 4115 | null | null | | btree | | | content | 1 | type_proc_last_cat | 4 | category | | 4115 | null | null | | btree | | +---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ mysql> describe battles; +---------------------+---------------------+------+-----+---------+-------+ | field | type | null | key | default | | +---------------------+---------------------+------+-----+---------+-------+ | id | bigint(20) unsigned | no | pri | null | | | status | tinyint(4) unsigned | no | | null | | | status_last_changed | int(11) unsigned | no | | null | | +---------------------+---------------------+------+-----+---------+-------+ mysql> show indexes battles; +---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ | table | non_unique | key_name | seq_in_index | column_name | collation | cardinality | sub_part | packed | null | index_type | comment | +---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ | battles | 0 | primary | 1 | id | | 1215 | null | null | | btree | | | battles | 0 | id_status | 1 | id | | 1215 | null | null | | btree | | | battles | 0 | id_status | 2 | status | | 1215 | null | null | | btree | | +---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
and output this:
mysql> explain -> select c.id id, type -> content c use index (type_proc_last_cat) -> left join battles b use index (id_status) on c.id = b.id -> type = 1 -> , processing_status = 1 -> , category in (13, 19) -> , status = 4 -> order last_change desc -> limit 100; +----+-------------+-------+--------+--------------------+--------------------+---------+-----------------------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | | +----+-------------+-------+--------+--------------------+--------------------+---------+-----------------------+------+--------------------------+ | 1 | simple | c | ref | type_proc_last_cat | type_proc_last_cat | 2 | const,const | 1352 | using where; using index | | 1 | simple | b | eq_ref | id_status | id_status | 9 | wtm_master.c.id,const | 1 | using where; using index | +----+-------------+-------+--------+--------------------+--------------------+---------+-----------------------+------+--------------------------+
the trouble rows count content table. appears mysql unable use both last_change , category in type_proc_last_cat index. if switch order of last_change , category, fewer rows selected results in filesort order by, meaning pulls matching rows database. worse, since there 100,000+ rows in both tables.
tables both innodb, keep in mind primary key appended every other index. index index type_proc_last_cat above behaves likes it's on (type, processing_status, last_change, category, id). aware change primary key battles (id, status) , drop id_status index (and may that).
edit: value type, category, processing_status, , status less 20% of total values. last_change , status_last_change unix timestamps.
edit: if use different index category
, last_change
in reverse order, this:
mysql> show indexes content; +---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ | table | non_unique | key_name | seq_in_index | column_name | collation | cardinality | sub_part | packed | null | index_type | comment | +---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ | content | 0 | primary | 1 | id | | 4115 | null | null | | btree | | | content | 1 | type_proc_cat_last | 1 | type | | 6 | null | null | | btree | | | content | 1 | type_proc_cat_last | 2 | processing_status | | 26 | null | null | | btree | | | content | 1 | type_proc_cat_last | 3 | category | | 228 | null | null | | btree | | | content | 1 | type_proc_cat_last | 4 | last_change | | 4115 | null | null | | btree | | +---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ mysql> explain select c.id id, type content c use index (type_proc_cat_last) left join battles b use index (id_status) on c.id = b.id type = 1 , processing_status = 1 , category in (13, 19) , status = 4 order last_change desc limit 100; +----+-------------+-------+-------+--------------------+--------------------+---------+-----------------------+------+------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | | +----+-------------+-------+-------+--------------------+--------------------+---------+-----------------------+------+------------------------------------------+ | 1 | simple | c | range | type_proc_cat_last | type_proc_cat_last | 10 | null | 165 | using where; using index; using filesort | | 1 | simple | b | ref | id_status | id_status | 9 | wtm_master.c.id,const | 1 | using where; using index | +----+-------------+-------+-------+--------------------+--------------------+---------+-----------------------+------+------------------------------------------+
the filesort worries me tells me mysql pulls matching rows first, before sorting. big problem when there 100,000+.
rows
field in explain
doesn't reflect number of rows read. reflects number of rows possible affected. doesn't rely on limit
, because limit
applied after plan has been calculated.
so don't need worry it.
also suggest swap last_change
, category
in type_proc_last_cat
mysql can try use last index part (last_change
) sorting purposes.
Comments
Post a Comment