1

У меня есть следующая таблицаMySQL, не выбирая правильный подсчет строк из индекса

CREATE TABLE `test_series_analysis_data` (
    `email` varchar(255) NOT NULL, 
    `mappingId` int(11) NOT NULL, 
    `packageId` varchar(255) NOT NULL, 
    `sectionName` varchar(255) NOT NULL, 
    `createdAt` datetime(3) DEFAULT NULL, 
    `marksObtained` float NOT NULL, 
    `updatedAt` datetime DEFAULT NULL, 
    `testMetaData` longtext, 
    PRIMARY KEY (`email`,`mappingId`,`packageId`,`sectionName`), 
    KEY `rank_index` (`mappingId`,`packageId`,`sectionName`,`marksObtained`), 
    KEY `mapping_package` (`mappingId`,`packageId`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 

Далее следует вывод из объяснения для запросов:

explain select rank 
from (
    select email, @i:[email protected]+1 as rank 
    from test_series_analysis_data ta 
    join (select @i:=0) va 
    where mappingId = ?1 
    and packageId = ?2 
    and sectionName = ?3 
    order by marksObtained desc 
) as inter 
where inter.email = ?4; 

+----+-------------+------------+------------+--------+----------------------------+-------------+---------+-------+-------+----------+--------------------------+ 
| id | select_type | table  | partitions | type | possible_keys    | key   | key_len | ref | rows | filtered | Extra     | 
+----+-------------+------------+------------+--------+----------------------------+-------------+---------+-------+-------+----------+--------------------------+ 
| 1 | PRIMARY  | <derived2> | NULL  | ref | <auto_key0>    | <auto_key0> | 767  | const | 10 | 100.00 | NULL      | 
| 2 | DERIVED  | <derived3> | NULL  | system | NULL      | NULL  | NULL | NULL |  1 | 100.00 | Using filesort   | 
| 2 | DERIVED  | ta   | NULL  | ref | rank_index,mapping_package | rank_index | 4  | const | 20160 |  1.00 | Using where; Using index | 
| 3 | DERIVED  | NULL  | NULL  | NULL | NULL      | NULL  | NULL | NULL | NULL |  NULL | No tables used   | 
+----+-------------+------------+------------+--------+----------------------------+-------------+---------+-------+-------+----------+--------------------------+ 

запроса оптимизатор мог бы использовать как индексы, но rank_index является индексом покрытия, поэтому он был выбран. Что меня удивляет выход следующего запроса:

explain select rank 
from ( 
    select email, @i:[email protected]+1 as rank 
    from test_series_analysis_data ta use index (mapping_package) 
    join (select @i:=0) va 
    where mappingId = ?1 
    and packageId = ?2 
    and sectionName = ?3 
    order by marksObtained desc 
) as inter 
where inter.email = ?4; 

+----+-------------+------------+------------+--------+-----------------+-----------------+---------+-------+-------+----------+-----------------------+ 
| id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref | rows | filtered | Extra     | 
+----+-------------+------------+------------+--------+-----------------+-----------------+---------+-------+-------+----------+-----------------------+ 
| 1 | PRIMARY  | <derived2> | NULL  | ref | <auto_key0>  | <auto_key0>  | 767  | const | 10 | 100.00 | NULL     | 
| 2 | DERIVED  | <derived3> | NULL  | system | NULL   | NULL   | NULL | NULL |  1 | 100.00 | Using filesort  | 
| 2 | DERIVED  | ta   | NULL  | ref | mapping_package | mapping_package | 4  | const | 19434 |  1.00 | Using index condition | 
| 3 | DERIVED  | NULL  | NULL  | NULL | NULL   | NULL   | NULL | NULL | NULL |  NULL | No tables used  | 
+----+-------------+------------+------------+--------+-----------------+-----------------+---------+-------+-------+----------+-----------------------+ 

Почему там rows меньшей (19434 < 20160), когда используется индекс mapping_package. rank_index может лучше выбрать то, что требуется, поэтому количество строк должно быть меньше в rank_index.

Значит ли это, что index_package лучше, чем rank_index для данного запроса?

Имеет ли эффект, что sectionName является varchar, поэтому оба индекса должны давать аналогичную производительность?

Также я предполагаю, что Using index condition выбирает только несколько строк из индекса и сканирует еще несколько. В то время как в случае Using where; Using index оптимизатор должен читать только индекс, а не таблицу, чтобы получать строки, а затем выбирает некоторые данные. Тогда почему Using where отсутствует при использовании rank_index?

Кроме того, почему key_len для mapping_package равен 4, если в индексе есть только два столбца?

Помогите оценить.

+0

Какой запрос (с индексом использования или без него) работает быстрее? –

ответ

1

(19434<20160) - Оба эти числа являются оценками. Для них это необычно. Готов поспорить, если бы вы сделали ANALYZE TABLE, оба изменились бы, возможно, изменив неравенство.

Обратите внимание на следующее: Using where; Using index по сравнению с Using index condition.

Но прежде всего позвольте напомнить, что в InnoDB столбцы PRIMARY KEY прикреплены к второстепенному ключу. Таким образом, фактически у вас есть

KEY `rank_index`  (`mappingId`,`packageId`,`sectionName`,`marksObtained`,`email`) 
KEY `mapping_package` (`mappingId`,`packageId`,`email`,`sectionName`) 

Теперь давайте решим, что оптимальный показатель должен быть: где mappingId = 1 и PackageID = 2 и имя раздела = 3 заказ по marksObtained убыв

    ??
  • Во-первых, = части WHERE: mappingId, packageId, sectionName, в любом порядке;
  • Тогда ORDER BY столбца (ы): marksObtained
  • Bonus: Наконец, если email (единственный другой столбец упоминается нигде в SELECT) находится в ключе, то это будет «Перекрытие».

Это говорит о том, что rank_index является «идеальным», а другой индекс не очень хорош. Увы, EXPLAIN не ясно это говорит.

Вы тоже могли бы понял это - все, что вам нужно, это изучить мой блог: http://mysql.rjweb.org/doc.php/index_cookbook_mysql (К сожалению, это уже поздно, и я получаю нахальный.)

Другие советы:

  • Не слепо использовать (255). Когда необходима таблица tmp, это может сделать таблицу tmp более крупной, следовательно, менее эффективной. Понизьте предел к чему-то разумному. Или ...
  • Если это огромный стол, вы действительно должны «нормализовать» строки, заменив их, возможно, 2-байтным SMALLINT UNSIGNED. Это улучшит производительность другими способами, например, уменьшит затраты на ввод-вывод. (ОК, 20 рядов довольно малы, поэтому это может не распространяться.)

Почему key_len 4? Это означает, что использовался один столбец, а именно 4-байтовый INTmappingId. Я бы ожидал, что он также будет использовать второй столбец. Итак, я в тупике. EXPLAIN FORMAT=JSON SELECT ... может предоставить дополнительные подсказки.

+0

Можете ли вы указать на индикацию рефлексии mysql? Я выполнил таблицы анализа, и цифры не изменились. Действительно, это было «Использование где; Используя индекс, который заставлял меня думать, что «rank_index» действительно лучше. Кроме того, это не такая огромная таблица (как только 5L записей). после поиска индекса возвращается <5000 строк. –

+1

Возможно, это ?: http://dev.mysql.com/doc/refman/5.5/en/innodb-index-types.html (последний раздел этой страницы) –

+0

5L = 5 lakh = 500K? –