SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 10.12.2015 16:05:05

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 847

Выяснение равенства строк с учетом пробелов на конце

Недавно столкнулся с прочно забытым правилом, согласно которому MySQL применяет оператор = к строкам CHAR/VARCHAR без учета пробелов на конце:

Код:

mysql> SELECT 'a' = 'a   ';
+--------------+
| 'a' = 'a   ' |
+--------------+
|            1 |
+--------------+

С учетом пробелов сравнивает LIKE:

Код:

mysql> SELECT 'a' LIKE 'a   ';
+-----------------+
| 'a' LIKE 'a   ' |
+-----------------+
|               0 |
+-----------------+

Но LIKE хуже пользуется индексом на колонке url (уникальный ключ на всю длину):

Код:

mysql> EXPLAIN SELECT * FROM pages WHERE url = '/'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pages
         type: const
possible_keys: url
          key: url
      key_len: 258
          ref: const
         rows: 1
        Extra:
1 row in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM pages WHERE url LIKE '/'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pages
         type: range
possible_keys: url
          key: url
      key_len: 258
          ref: NULL
         rows: 1
        Extra: Using where
1 row in set (0.00 sec)

Как сравнивать строки с учетом пробелов, при этом наиболее эффективно используя индекс?

Неактивен

 

#2 10.12.2015 16:13:47

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Выяснение равенства строк с учетом пробелов на конце

А в чем проблема с индексом при использовании LIKE?

Не забудь, что для CHAR и VARCHAR концевые пробелы вообще не сохраняются в базе.

Неактивен

 

#3 10.12.2015 16:24:02

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 847

Re: Выяснение равенства строк с учетом пробелов на конце

А в чем проблема с индексом при использовании LIKE?

ref у explain поприятней выглядит. Для = - const, для LIKE - using where.
Такое впечатление, что для LIKE он не хочет использовать индекс.

Не забудь, что для CHAR и VARCHAR концевые пробелы вообще не сохраняются в базе.

Забыл smile
Но в данном случае проблема обратная: пробелы есть в сравниваемой с базой строке. И сравнение должно заканчиваться неудачей, если строки отличаются из-за концевых пробелов.

На практике ситуация такая: серверу приходит адрес /   с пробелами на конце. Оператор = скажет, что это то же самое, что /, механизм сайта как ни в чем не бывало отдаст по адресу /   главную страницу. В результате у поисковика в индексе появляется дубликат главной страницы, и сеошники падают в обморок smile (случай из жизни).

Неактивен

 

#4 10.12.2015 16:28:26

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Выяснение равенства строк с учетом пробелов на конце

LazY написал:

Такое впечатление, что для LIKE он не хочет использовать индекс.

Это не доказательство. Должно быть по скорости так же.

Оператор = думает, что вдруг там был тоже пробел, но съелся при записи в базу.

Неактивен

 

#5 10.12.2015 16:41:50

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 847

Re: Выяснение равенства строк с учетом пробелов на конце

Это не доказательство. Должно быть по скорости так же.

По скорости и так 0.00, и так 0.00 - таблица 100 записей smile

Неактивен

 

#6 10.12.2015 16:51:03

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 847

Re: Выяснение равенства строк с учетом пробелов на конце

Просто анализ путей запроса - важная часть механизма сайта, срабатывает при каждом запросе. Хотелось сделать ее максимально быстрой.
Если LIKE нормально - то и ладно.

Неактивен

 

#7 10.12.2015 23:51:18

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Выяснение равенства строк с учетом пробелов на конце

Сделай миллион записей и проверь. Вижу только то, что = делает проверку на точное совпадение, а LIKE на range. Хотя очевидно, что range достаточно узкий, это интересный вопрос почему range.

Кстати, у тебя может быть еще одна проблема. В данном случае с большими и маленькими буквами:

mysql> select 'a'='A';
+---------+
| 'a'='A' |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

mysql> select 'a' LIKE 'A';
+--------------+
| 'a' LIKE 'A' |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)


Решение:
SELECT * FROM pages WHERE url = BINARY '/'\G

Неактивен

 

#8 11.12.2015 18:00:46

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 847

Re: Выяснение равенства строк с учетом пробелов на конце

это интересный вопрос почему range

Видимо, потому что не точное равенство. LIKE по правой части оптимизатор наверняка рассматривает как range, а частный случай, когда LIKE без процентов, он отдельно не учитывает.
Кстати, для = BINARY тоже показывает range.

Насчет использования индекса. Дело тут, похоже, в наборе колонок для SELECT.
Если вместо SELECT * сделать SELECT COUNT(*), то и =, и LIKE, и = BINARY дают Using where; Using index.

По скорости все оказались примерно одинаковыми.

Кстати, у тебя может быть еще одна проблема. В данном случае с большими и маленькими буквами:

Да. Но ее решение - это вопрос отдельный.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson