MySQL имеет по существу один метод индексации: BTree.(Да, есть также Spatial и Fulltext, но это другое обсуждение.)
Как только вы поймете, как работает BTree (см. Википедию), мы можем обсудить, что входит в конечные узлы в InnoDB.
Случай 1: «Дерево данных» BTree содержит все столбцы и сортируется в соответствии с PRIMARY KEY
.В MySQL PK имеет значение по определению , "UNIQUE" и "Clustered".(У других поставщиков есть другие варианты.)
Случай 2: «Вторичный» INDEX
хранится в отдельном BTree.В конечных узлах находятся (1) столбцы, определенные во вторичном индексе, плюс копии столбцов PK.Чтобы завершить SELECT
с использованием вторичного индекса, он должен сначала извлечь PK с использованием индекса BTree, а затем извлечь данные через данные BTree.(Если индекс «покрывает», этот второй шаг не требуется.)
В MySQL не существует «Rownum».
BTrees на самом деле являются деревьями B +, что позволяет выполнять сканирование диапазона.более эффективный.
InnoDB помещает все BTrees для данной таблицы (один для данных + PK, один для каждого вторичного индекса) в некоторое табличное пространство.Табличное пространство является либо общим (ibdata1
файл), либо табличным (файл tablename.ibd
), либо (в более новых версиях) файлом «табличного пространства», которое может содержать несколько таблиц.
Предостережение: То, что я описал, относится к InnoDB MySQL и, вероятно, не подходит для любого другого движка.
Я не знаю хорошего инструмента для проверки BTrees InnoDB, не вдаваясь в подробности.Для версии Percona:
SELECT i.INDEX_NAME as Index_Name,
IF(ROWS_READ IS NULL, 'Unused',
IF(ROWS_READ > 2e9, 'Overflow', ROWS_READ)) as Rows_Read
FROM (
SELECT DISTINCT TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
FROM information_schema.STATISTICS
) i
LEFT JOIN information_schema.INDEX_STATISTICS s
ON i.TABLE_SCHEMA = s.TABLE_SCHEMA
AND i.TABLE_NAME = s.TABLE_NAME
AND i.INDEX_NAME = s.INDEX_NAME
WHERE i.TABLE_SCHEMA = ?
AND i.TABLE_NAME = ?
ORDER BY IF(i.INDEX_NAME = 'PRIMARY', 0, 1)
Для MySQL (Oracle):
SELECT last_update,
n_rows,
'Data & PK' AS 'Type',
clustered_index_size * 16384 AS Bytes,
ROUND(clustered_index_size * 16384 / n_rows) AS 'Bytes/row',
clustered_index_size AS Pages,
ROUND(n_rows / clustered_index_size) AS 'Rows/page'
FROM mysql.innodb_table_stats
WHERE ( ( database_name = ? AND table_name = ? )
OR ( database_name = LOWER(?) AND table_name = LOWER(?)
UNION
SELECT last_update,
n_rows,
'Secondary Indexes' AS 'BTrees',
sum_of_other_index_sizes * 16384 AS Bytes,
ROUND(sum_of_other_index_sizes * 16384 / n_rows) AS 'Bytes/row',
sum_of_other_index_sizes AS Pages,
ROUND(n_rows / sum_of_other_index_sizes) AS 'Rows/page'
FROM mysql.innodb_table_stats
WHERE ( ( database_name = ? AND table_name = ? )
OR ( database_name = LOWER(?) AND table_name = LOWER(?)
AND sum_of_other_index_sizes > 0