Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Вопрос по limit и UNIQUE KEY
Форумы портала PHP.SU » » Вопросы новичков » Вопрос по limit и UNIQUE KEY

Страниц (1): [1]
 

1. Artix - 27 Декабря, 2017 - 16:13:00 - перейти к сообщению
Если я использую в бд UNIQUE KEY `login` (`login`), LIMIT 1 можно в запросе не использовать?
PHP:
скопировать код в буфер обмена
  1.  
  2. $login = mysqli_query($mysqli_connect, "SELECT * FROM `users` WHERE `login` = '".$_POST['login']."' LIMIT 1");
  3.         if(mysqli_num_rows($login) > 0)
  4.                 $error .= 'Пользователь с таким логином уже зарегистрирован, используйте другой.';
  5.  
2. rgl - 28 Декабря, 2017 - 12:18:05 - перейти к сообщению
Во-первых, если нужно узнать только кол-во записей (предположительно 0 или 1) незачем использовать SELECT * ибо выбирает все поля, а они не нужны, лишняя работа, достаточно какое-нибудь одно поле. Другой вариант - использовать SELECT COUNT(*) только тогда проверку условия нужно будет изменить.
Во-вторых, никогда не передавайте что-либо, полученное от пользователя, напрямую, без обработки в SQL-запрос. В вашем случае вместо $_POST['login'] используйте addslashes($_POST['login'])
В третьих, да, видимо LIMIT 1 в таком случае не нужен.
3. Artix - 28 Декабря, 2017 - 12:24:27 - перейти к сообщению
rgl пишет:
незачем использовать SELECT * ибо выбирает все поля, а они не нужны, лишняя работа,

"SELECT `login` FROM `users` WHERE `login` = '".$_POST['login']."'"
Я правильно понял???
4. rgl - 28 Декабря, 2017 - 14:19:11 - перейти к сообщению
"SELECT `login` FROM `users` WHERE `login` = '".addslashes($_POST['login'])."'"
5. Строитель - 28 Декабря, 2017 - 15:24:20 - перейти к сообщению
Artix пишет:
Если я использую в бд UNIQUE KEY `login` (`login`), LIMIT 1 можно в запросе не использовать?
Лично я далеко не эксперт в работе sql-баз данных, но если память мне не изменяет, с помощью оператора LIMIT можно существенно увеличить производительность sql-запроса, т.к. LIMIT прерывает его выполнение. Попробую объяснить на вашем примере:
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM `users` WHERE `login` = 'login'
Эта команда будет искать соответствия во всей таблице `users`, невзирая на уже найденное ранее соответствие условию WHERE `login` = 'login'. Иначе говоря, если в таблице 100 000 строк, то этим запросом будут затронуты все эти строки.

В случае с оператором LIMIT
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM `users` WHERE `login` = 'login' LIMIT 1
LIMIT 1 завершает поиск по БД после первого найденного соответствия. Вывод очевиден.

P.S.: Поправьте меня, если где-то ошибся.
6. Мелкий - 28 Декабря, 2017 - 15:50:09 - перейти к сообщению
Если есть уникальное ограничение и мы по нему ищем - то limit 1 бесполезен, т.к. планировщик и так знает, что по уникальному индексу не умеет смысла продолжать искать после первого совпадения.

rgl пишет:
лишняя работа, достаточно какое-нибудь одно поле

Есть большая разница между "какое-нибудь одно поле" и некоторое определённое поле.
Константу select 1 или выборка непосредственно полей по которым искали - допустимо использовать index only scan.
select primary_key_field - для mysql/innodb одно и то же, можно index only scan получить. Для других надо уточнять
выбор любого inline поля - надо идти читать его из таблицы
выбор external поля (большого text, например) - надо идти сначала в таблицу, затем ещё вычитывать отдельно лежащее содержимое этого файла

А для передачи данных для запроса - есть prepared statements. В mysql, впрочем, на редкость неудобные и лучше использовать pdo.
Подстановка данных в текст запроса должна настораживать сама по себе.
7. Artix - 28 Декабря, 2017 - 15:50:13 - перейти к сообщению
Строитель пишет:
Artix пишет:
Если я использую в бд UNIQUE KEY `login` (`login`), LIMIT 1 можно в запросе не использовать?
Лично я далеко не эксперт в работе sql-баз данных, но если память мне не изменяет, с помощью оператора LIMIT можно существенно увеличить производительность sql-запроса, т.к. LIMIT прерывает его выполнение. Попробую объяснить на вашем примере:
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM `users` WHERE `login` = 'login'
Эта команда будет искать соответствия во всей таблице `users`, невзирая на уже найденное ранее соответствие условию WHERE `login` = 'login'. Иначе говоря, если в таблице 100 000 строк, то этим запросом будут затронуты все эти строки.

В случае с оператором LIMIT
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM `users` WHERE `login` = 'login' LIMIT 1
LIMIT 1 завершает поиск по БД после первого найденного соответствия. Вывод очевиден.

P.S.: Поправьте меня, если где-то ошибся.

Это я знаю, тогда смысл с UNIQUE KEY ??
8. MouseZver - 29 Декабря, 2017 - 09:25:17 - перейти к сообщению
Запрос в любом случае просмотрит все записи подошедшие по критерию и только потом будет применен LIMIT 1
(Добавление)
производительность LIMIT играет другую роль.
(Добавление)
Мелкий пишет:
В mysql, впрочем, на редкость неудобные и лучше использовать pdo.

https://github[dot]com/MouseZver/Lerma
(Добавление)
rgl пишет:
В вашем случае вместо $_POST['login'] используйте addslashes($_POST['login'])


sql-injection
9. Мелкий - 29 Декабря, 2017 - 09:39:39 - перейти к сообщению
MouseZver пишет:
Запрос в любом случае просмотрит все записи подошедшие по критерию и только потом будет применен LIMIT 1

В общем случае утверждение неверно.
https://dev[dot]mysql[dot]com/doc/refman[dot][dot][dot]ptimization[dot]html
10. MouseZver - 29 Декабря, 2017 - 09:43:42 - перейти к сообщению
Мелкий пишет:
MouseZver пишет:
Запрос в любом случае просмотрит все записи подошедшие по критерию и только потом будет применен LIMIT 1

В общем случае утверждение неверно.
https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html


Не стоит путать производительность LIMIT с выведением результата и производительность LIMIT для поиска в таблице Подмигивание
11. Мелкий - 29 Декабря, 2017 - 10:11:35 - перейти к сообщению
MouseZver, а я и не путаю.
Имеющийся limit мало того, что не будет перебирать все совпадающие строки (за ненадобностью) - так ещё и может использовать вообще другой план запроса (основные моменты указаны в мануале, на который я сослался).

CODE (sql):
скопировать код в буфер обмена
  1. mysql> SELECT SQL_NO_CACHE * FROM bigtable WHERE i = 5435;
  2. +------+------+
  3. | id   | i    |
  4. +------+------+
  5. | 5435 | 5435 |
  6. +------+------+
  7. 1 row IN SET (0.11 sec)
  8.  
  9. mysql> SELECT SQL_NO_CACHE * FROM bigtable WHERE i = 5435;
  10. +------+------+
  11. | id   | i    |
  12. +------+------+
  13. | 5435 | 5435 |
  14. +------+------+
  15. 1 row IN SET (0.12 sec)
  16.  
  17. mysql> SELECT SQL_NO_CACHE * FROM bigtable WHERE i = 5435 LIMIT 1;
  18. +------+------+
  19. | id   | i    |
  20. +------+------+
  21. | 5435 | 5435 |
  22. +------+------+
  23. 1 row IN SET (0.00 sec)
  24.  
  25. mysql> SELECT SQL_NO_CACHE * FROM bigtable WHERE i = 5435 LIMIT 1;
  26. +------+------+
  27. | id   | i    |
  28. +------+------+
  29. | 5435 | 5435 |
  30. +------+------+
  31. 1 row IN SET (0.01 sec)
  32.  
  33. mysql> EXPLAIN SELECT SQL_NO_CACHE * FROM bigtable WHERE i = 5435 LIMIT 1;
  34. +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
  35. | id | select_type | TABLE    | type | possible_keys | KEY  | key_len | ref  | rows    | Extra       |
  36. +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
  37. |  1 | SIMPLE      | bigtable | ALL  | NULL          | NULL | NULL    | NULL | 1000379 | USING WHERE |
  38. +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
  39. 1 row IN SET (0.00 sec)
  40.  
  41. mysql> EXPLAIN SELECT SQL_NO_CACHE * FROM bigtable WHERE i = 5435;
  42. +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
  43. | id | select_type | TABLE    | type | possible_keys | KEY  | key_len | ref  | rows    | Extra       |
  44. +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
  45. |  1 | SIMPLE      | bigtable | ALL  | NULL          | NULL | NULL    | NULL | 1000379 | USING WHERE |
  46. +----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
  47. 1 row IN SET (0.00 sec)
  48.  

Мяч у вас. Докажите своё высказывание и объясните, почему limit 1 прервал seqscan преждевременно. В табличке лям строк, искомый i где-то в начале.

Для уникального индекса это всё, естественно, не играет роли, т.к. планировщик изначально знает гарантированную селективность уникального ограничения.
12. Строитель - 29 Декабря, 2017 - 11:50:54 - перейти к сообщению
Мелкий пишет:
Имеющийся limit мало того, что не будет перебирать все совпадающие строки (за ненадобностью) - так ещё и может использовать вообще другой план запроса
Лично я уже запутался ... Ответьте мне, пожалуйста, моё утверждение о повышении производительности за счёт использования оператора LIMIT истинно? Или ложно?
13. Мелкий - 29 Декабря, 2017 - 13:12:40 - перейти к сообщению
Строитель пишет:
моё утверждение о повышении производительности за счёт использования оператора LIMIT истинно? Или ложно?

Два случая:
0) если есть unique по тому что ищем - то лимит роли не играет (гхм, ну кроме limit 0 - эта замечательная вещь даже выполняться не будет, ответит 0 строк сразу на этапе разбора)
Но и вреда от limit 1 не будет.
1) если уникального ограничения нет - лимит играет свою роль и прерывает выполнение запроса сразу по достижении нужного числа совпадений. И планировщик может менять план опираясь на знание того что надо достать только часть строк. Что совпадает с наблюдениями, если MouseZver не докажет обратное.
14. Строитель - 29 Декабря, 2017 - 13:39:44 - перейти к сообщению
Мелкий, благодарю )

 

Powered by ExBB FM 1.0 RC1