Могу ли я привести VARCHAR к INT, не нарушая INDEX? - PullRequest
0 голосов
/ 13 января 2020

Нужен поиск по таблице foo

foo структура

id | что-то

Существует поле INDEX для поля something

Я хочу найти МЕЖДУ AS INT:

SELECT CAST(something as INT) as something_int FROM foo foo_1
WHERE something_int > 1 AND something_int < 9999

В этом случае INDEX будет быть использованным или сломанным?

Ответы [ 2 ]

1 голос
/ 15 января 2020
WHERE some_varchar BETWEEN '1' AND '2000'  -- fast but probably incorrect
WHERE some_varchar BETWEEN 1 AND 2000      -- slow but correct
WHERE some_int BETWEEN '1' AND '2000'      -- fast
WHERE some_int BETWEEN 1 AND 2000          -- fast (same as previous)

Что происходит?

  • При сравнении текста с цифрой c сторона текста преобразуется в цифру c, а затем выполняется сравнение чисел c.
  • Сравнение текста с текстом делает сравнение строк; от цифр c до цифр c делает сравнение чисел c.
  • Выше я говорю «медленный», означающий, что индекс не может быть использован; «быстрый», если можно использовать индекс.
  • «Неверный» имеет ту же проблему, что и сортировка набора чисел в VARCHAR, а затем задается вопросом, почему список не в порядке: 1,10 , 11, ..., 19,2,20, ..., 29,3, ...
  • CAST() - это просто явная версия неявного преобразования, о котором я здесь говорю.
  • CAST('2000' TO INT) выполняется "во время компиляции", поэтому оптимизатор видит это просто 2000 (цифра c, без вызова функции).
  • some_varchar >= 1 с другой стороны, во втором примере выше превращается в CAST(some_varchar TO INT) >= 1.
  • Как правило, «скрытие столбца в вызове функции запрещает использование индекса. См.« sargable »в Википедии.
0 голосов
/ 13 января 2020

Нет, индекс не будет использоваться.

CREATE TABLE foo(something varchar(20) primary key) engine=myisam;
INSERT INTO foo VALUES ('1|abc'), ('3456|def');

DESCRIBE SELECT * FROM foo WHERE CAST(something as INT) BETWEEN 1 AND 2000;
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
|    1 | SIMPLE      | tt    | index | NULL          | PRIMARY | 82      | NULL |    2 | Using where; Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+

DESCRIBE SELECT * FROM foo WHERE something BETWEEN '1' AND '2000';
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
|    1 | SIMPLE      | tt    | range | PRIMARY       | PRIMARY | 82      | NULL |    1 | Using where; Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+

Обратите внимание, что possible_keys равно NULL для первого запроса (и rows найдено 2).

Примечание: это может произойти, даже если набор символов запроса не совпадает с набором символов индекса.

Создайте отдельный индекс INT (например, используя синтаксис index функции ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...