MySQL index + математические операторы - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть RatingTable:

UserID int,
Rating int,
BanMask int,
index rating_index (Rating DESC),
index ban_index (BanMask ASC)

Допустим, в этой таблице более 5 миллионов строк и только ~ 100 действительно заблокированных пользователей.

Будет ли оптимизирован запрос на выборку, если я использую битовые математические операции с индексированным полем?Являются ли эти 2 запроса будут использовать оптимизацию индекса?

SELECT * FROM ProfileTable 
WHERE BanMask > 0 
ORDER BY Rating DESC LIMIT 10;

против

SELECT * FromProfileTable 
WHERE (BanMask & (1 << 2)) > 0 
ORDER BY Rating DESC LIMIT 10;

И второй вопрос.Должен ли я добавить индекс для полей Rating + BanMask для лучшей оптимизации?Как это:

CREATE INDEX rating_ban_index ON ProfileTable (Rating DESC, BanMask ASC)

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Вот обходной путь для BanMask > 0, но не для другого запроса , который отличается .

Вместо того, чтобы BanMask имел кучу разных ненулевых значений,одно значение, которое говорит о запрете.

Один из способов - это иметь другой столбец, который будет просто true / false, и делать

WHERE banned = 1  ORDER BY Rating DESC  LIMIT ..
INDEX(banned, Rating)  -- in _this_ order

Вариант этого - иметь «сгенерированный» столбец.(если у вас достаточно новая версия MySQL / MariaDB), которая вычисляет значение true / false из BanMask.

Реальное преимущество вышеизложенного состоит в том, что LIMIT можно увидеть и использовать.То есть нужно просмотреть только 10 строк.Все остальные решения должны сканировать множество строк, возможно, всю таблицу.

Вот несколько общих правил:

  • первый столбец (столбцы) индексадолжен быть проверен с =.
  • После того, как вы протестируете столбец с диапазоном (BanMask > 0), столбец можно использовать, но дальнейшие столбцы бесполезны.
  • Скрытие столбцав функции (в вашем случае & - это функция), делает невозможным использование этого столбца в индексе.

Для исходного вопроса и без сгенерированного столбца, тогда я ожидал бы INDEX(Rating) быть единственным полезным индексом.Поскольку вы запрашиваете все столбцы (SELECT *), нецелесообразно расширять его до "покрытия".

0 голосов
/ 17 февраля 2019

Вы можете сами подтвердить, какие индексы используются для данного запроса, используя EXPLAIN .

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: RatingTable
         type: index
possible_keys: ban_index
          key: rating_index
      key_len: 5
          ref: NULL
         rows: 10
        Extra: Using where

Вы должны изучить эту страницу руководства, чтобы получить объяснение вывода: https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

Я ожидаю, что для вашего запроса нельзя использовать индекс с помощью выражения.

WHERE (BanMask & (1 << 2)) > 0

В отчете EXPLAIN показано:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: RatingTable
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10
        Extra: Using where; Using filesort

В общем случае индекс нельзя использовать, если на ваш индексированный столбец в левой части оператора сравнения есть ссылка в выражении или вфункция.Это должен быть «пустой» столбец.

Индексы работают при поиске значений, которые находятся вместе в порядке сортировки индекса.Ваш пример ищет каждое 4-е значение в BanMask, те, у которых установлен бит в 4-м месте.Эти значения не являются последовательными, они распределены.MySQL не будет использовать индекс для поиска во всем диапазоне значений, подобных этому, потому что в конечном итоге это будет так же дорого, как сканирование всей таблицы.

Что касается вашего второго вопроса, о добавлении индекса на (Rating DESC, BanMask ASC), ответ может помочь избежать сортировки файлов.Но это не поможет найти BanMask.

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: RatingTable
   partitions: NULL
         type: index
possible_keys: NULL
          key: Rating
      key_len: 10
          ref: NULL
         rows: 10
        Extra: Using where
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...