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

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Вопрос по limit и UNIQUE KEY

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


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

> Без описания
Artix
Отправлено: 27 Декабря, 2017 - 16:13:00
Post Id


Новичок


Покинул форум
Сообщений всего: 35
Дата рег-ции: Дек. 2017  


Помог: 0 раз(а)




Если я использую в бд 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.  

(Отредактировано автором: 28 Декабря, 2017 - 11:20:35)

 
 Top
rgl
Отправлено: 28 Декабря, 2017 - 12:18:05
Post Id



Новичок


Покинул форум
Сообщений всего: 56
Дата рег-ции: Авг. 2017  
Откуда: замкадье


Помог: 1 раз(а)




Во-первых, если нужно узнать только кол-во записей (предположительно 0 или 1) незачем использовать SELECT * ибо выбирает все поля, а они не нужны, лишняя работа, достаточно какое-нибудь одно поле. Другой вариант - использовать SELECT COUNT(*) только тогда проверку условия нужно будет изменить.
Во-вторых, никогда не передавайте что-либо, полученное от пользователя, напрямую, без обработки в SQL-запрос. В вашем случае вместо $_POST['login'] используйте addslashes($_POST['login'])
В третьих, да, видимо LIMIT 1 в таком случае не нужен.
 
 Top
Artix
Отправлено: 28 Декабря, 2017 - 12:24:27
Post Id


Новичок


Покинул форум
Сообщений всего: 35
Дата рег-ции: Дек. 2017  


Помог: 0 раз(а)




rgl пишет:
незачем использовать SELECT * ибо выбирает все поля, а они не нужны, лишняя работа,

"SELECT `login` FROM `users` WHERE `login` = '".$_POST['login']."'"
Я правильно понял???

(Отредактировано автором: 28 Декабря, 2017 - 12:25:35)

 
 Top
rgl
Отправлено: 28 Декабря, 2017 - 14:19:11
Post Id



Новичок


Покинул форум
Сообщений всего: 56
Дата рег-ции: Авг. 2017  
Откуда: замкадье


Помог: 1 раз(а)




"SELECT `login` FROM `users` WHERE `login` = '".addslashes($_POST['login'])."'"
 
 Top
Строитель Модератор
Отправлено: 28 Декабря, 2017 - 15:24:20
Post Id



Участник


Покинул форум
Сообщений всего: 1580
Дата рег-ции: Февр. 2014  
Откуда: Украина


Помог: 73 раз(а)




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.: Поправьте меня, если где-то ошибся.
 
 Top
Мелкий Супермодератор
Отправлено: 28 Декабря, 2017 - 15:50:09
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




Если есть уникальное ограничение и мы по нему ищем - то limit 1 бесполезен, т.к. планировщик и так знает, что по уникальному индексу не умеет смысла продолжать искать после первого совпадения.

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

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

А для передачи данных для запроса - есть prepared statements. В mysql, впрочем, на редкость неудобные и лучше использовать pdo.
Подстановка данных в текст запроса должна настораживать сама по себе.


-----
PostgreSQL DBA
 
 Top
Artix
Отправлено: 28 Декабря, 2017 - 15:50:13
Post Id


Новичок


Покинул форум
Сообщений всего: 35
Дата рег-ции: Дек. 2017  


Помог: 0 раз(а)




Строитель пишет:
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 ??
 
 Top
MouseZver
Отправлено: 29 Декабря, 2017 - 09:25:17
Post Id



Новичок


Покинул форум
Сообщений всего: 58
Дата рег-ции: Июнь 2017  
Откуда: php.ru


Помог: 1 раз(а)




Запрос в любом случае просмотрит все записи подошедшие по критерию и только потом будет применен LIMIT 1
(Добавление)
производительность LIMIT играет другую роль.
(Добавление)
Мелкий пишет:
В mysql, впрочем, на редкость неудобные и лучше использовать pdo.

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


sql-injection
 
 Top
Мелкий Супермодератор
Отправлено: 29 Декабря, 2017 - 09:39:39
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




MouseZver пишет:
Запрос в любом случае просмотрит все записи подошедшие по критерию и только потом будет применен LIMIT 1

В общем случае утверждение неверно.
https://dev[dot]mysql[dot]com/doc/refman[dot][dot][dot]ptimization[dot]html


-----
PostgreSQL DBA
 
 Top
MouseZver
Отправлено: 29 Декабря, 2017 - 09:43:42
Post Id



Новичок


Покинул форум
Сообщений всего: 58
Дата рег-ции: Июнь 2017  
Откуда: php.ru


Помог: 1 раз(а)




Мелкий пишет:
MouseZver пишет:
Запрос в любом случае просмотрит все записи подошедшие по критерию и только потом будет применен LIMIT 1

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


Не стоит путать производительность LIMIT с выведением результата и производительность LIMIT для поиска в таблице Подмигивание
 
 Top
Мелкий Супермодератор
Отправлено: 29 Декабря, 2017 - 10:11:35
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




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 где-то в начале.

Для уникального индекса это всё, естественно, не играет роли, т.к. планировщик изначально знает гарантированную селективность уникального ограничения.


-----
PostgreSQL DBA
 
 Top
Строитель Модератор
Отправлено: 29 Декабря, 2017 - 11:50:54
Post Id



Участник


Покинул форум
Сообщений всего: 1580
Дата рег-ции: Февр. 2014  
Откуда: Украина


Помог: 73 раз(а)




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



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




Строитель пишет:
моё утверждение о повышении производительности за счёт использования оператора LIMIT истинно? Или ложно?

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


-----
PostgreSQL DBA
 
 Top
Строитель Модератор
Отправлено: 29 Декабря, 2017 - 13:39:44
Post Id



Участник


Покинул форум
Сообщений всего: 1580
Дата рег-ции: Февр. 2014  
Откуда: Украина


Помог: 73 раз(а)




Мелкий, благодарю )
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB