Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   www.boolean.name > Веб-программирование > PHP / MySQL

PHP / MySQL Создание динамических Веб-ресурсов

Ответ
 
Опции темы
Старый 03.09.2015, 07:51   #1
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
[MySql] Оператор сравнения IN

Что-то не могу нагуглить, есть ли у оператора IN ограничения. Сколько значений может принимать этот оператор? 100 принимает, проверено, а 1000? И стоит ли обновлять записи в базе таким запросом на 1000 вхождений или лучше 10 запросов по 100?
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2015, 11:03   #2
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Скорость работы IN, в зависимости от запроса может умножать сложность запроса кратной элементов в IN.
Так что если делаешь запрос на IN 10 ID например, то это скорее всего приведет к 10 кратному усложнению запроса, следственно в 10 дольше будет генерировать ответ. И это в хорошем случае когда индексы используются.
Без индексов все может быть похуже, если первым используется другое поле, и затем из профильтрованных значений нужно делать проверку. То либо будет создаваться мелкий временный индекс по меньшему списку проверямых данных, и еще одна итерация по полям для сравнения, либо вообще O(a*b), что я надеюсь в дб движке избежали используя временный индекс.
Если используется временный индекс, то это использует RAM, индексы обычно легкие.

Не смотря на все это, использование IN с очень большими списками не рекомендуется.
Порой можно избежать подобного и структурировать данные более удобно для таких целей.
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
pax (03.09.2015), St_AnGer (03.09.2015)
Старый 03.09.2015, 14:03   #3
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
Ответ: [MySql] Оператор сравнения IN

У меня задача - сервер оповещений оптимизировать. Я беру из базы LIMIT offset, 1000 записей, по ним вызываю оповещение в соц сети, потом мне надо этим записям записать дату последней нотификации. Так по всей базе пользователей данной соц сети. Пользователи других соц сетей тоже в этой базе приустствуют. По полю user_id из соц сети у меня есть индекс.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2015, 14:20   #4
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Немного запутался когда ты говоришь "база". Ты имеешь ввиду "таблица"?
У тебя в одной таблице все пользователи, с колонкой "соц_сеть"?

И тебе нужно пробежаться по всем пользователям определенной соц сети, послать им оповещение (соц. сети API), и затем записать дату оповещения?

Я не совсем вижу вообще зачем тебе IN здесь.
Сортируешь по user_id (он не изменный и только увеличивается). И далее делаешь выборку например 128 пользователей, далее шлешь им оповещания и обновляешь им notification_date, при этом тут проще будет использовать user_id больше и меньше чем первый и последний в этом списке.

Затем делаешь снова ту же выборку, только уже с дополнительным условием: user_id > last_user_id - где last_user_id самый большой последний user_id. И повторяешь все те же операции как и раньше.
И так по циклу, пока возвратимый результат не вернет 0 записей.

Что-то типо (псевдокод)

var last_user_id 0;

// repeat as long as there are users
while(true) {
    
// select batch of users
    
users "SELECT users WHERE user_id > " last_user_id " AND social_network = 'vk' ORDER BY user_id ASC LIMIT 128";

    
// no more users left to notify
    
if (users.length === 0)
        break;

    
// send notification
    
for(user in users)
        
send_notification(user)

    
// get first user_id and last user_id
    
var first_user_id users[0].id;
    
last_user_id users[users.length 1].id;

    
// update notification date of users
    
"UPDATE users WHERE user_id >= " first_user_id " AND user_id <= " last_user_id " SET notification_date = date";

Такой подход масштабируется с любым размером таблицы. Если больше записей будет, он всего лишь займет немного дольше времени.
Также увеличивая размер batch'а (128 в данном примере), ты больше заполнишь оперативки, но можешь быстрее обработать всю таблицу, снизив число запросов и парсинга.

Также такие вещи нужно писать не в блокируемом языке, с учетом того что send_notification может блокировать. Если он блокирует (PHP или Python), то у тебя этот скрипт займет ужасно много времени.
В идеале тебе нужно делать скрипт где send_notification выполняется паралельно с ограниченным числом.
Также лучше вообще параллелить батчи тоже, паралельно обрабатывая скажем 8 пачек по 128 пользователей.

В node.js такое легко параллелизуется, и будет очень шустро работать.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
pax (03.09.2015)
Старый 03.09.2015, 14:29   #5
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
Ответ: [MySql] Оператор сравнения IN

Сообщение от moka Посмотреть сообщение
Немного запутался когда ты говоришь "база". Ты имеешь ввиду "таблица"?
У тебя в одной таблице все пользователи, с колонкой "соц_сеть"?

И тебе нужно пробежаться по всем пользователям определенной соц сети, послать им оповещение (соц. сети API), и затем записать дату оповещения?
Сорри, да, так и есть.

Но тут дело такое - я выбираю только тех пользователей, которые логинились менее месяца назад (во время оповещения кто-то может залогиниться к примеру и нарушить порядок). Плюс АПИ соц сети возвращает id пользователей, которым дошло оповещение. Хотелось бы записать только тех, кому действительно оно дошло.

Сервер нотификаций работал в отдельном потоке, так что на работу основного сервера не влиял. Сейчас я его в отдельное приложении вынес. Все пишу на C# (Debian/Mono).
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2015, 15:38   #6
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Сообщение от pax Посмотреть сообщение
Но тут дело такое - я выбираю только тех пользователей, которые логинились менее месяца назад (во время оповещения кто-то может залогиниться к примеру и нарушить порядок).
Не нарушит, т.к. у тебя идет четкий порядок по user_id, который не изменный.
Следственно в условие запроса можешь добавить что пользователь логинился тогда-то. И даже если кто-то залогинится, это ок, т.к. у тебя сортировка и условие зависят от user_id.

Сообщение от pax Посмотреть сообщение
Плюс АПИ соц сети возвращает id пользователей, которым дошло оповещение. Хотелось бы записать только тех, кому действительно оно дошло.
А для посылки notification, ты в API шлешь массив с id'шками, или каждому пользователю индивидуально?
Главное не запускай этот скрипт рассылки пока не закончилось выполнение прошлого запуска, и тогда не будет конфликтов.

Сообщение от pax Посмотреть сообщение
Сервер нотификаций работал в отдельном потоке, так что на работу основного сервера не влиял. Сейчас я его в отдельное приложении вынес. Все пишу на C# (Debian/Mono).
Это хорошо чтобы не загрязнять основной процесс API.
Но нужна паралеллизация по задачкам в процессе. Но это не критично.
Зависит как быстро будет работать рассылка на данный момент, если медленно (10+ секунд), то стоит подумать о паралеллизации.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
pax (03.09.2015)
Старый 03.09.2015, 21:53   #7
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
Ответ: [MySql] Оператор сравнения IN

Ух, ну и спор начался...

Сообщение от moka Посмотреть сообщение
Не нарушит, т.к. у тебя идет четкий порядок по user_id, который не изменный.
Запрос примерно такого плана:
"SELECT * 
FROM users 
WHERE sn = 'vk' AND DATE_ADD(last_login, INTERVAL 31 day) > NOW() 
ORDER BY id 
LIMIT @offset, 1000" 
Потом вызываю апи соц сети, в одном запросе не более 100 id. т.е. 10 раз. Это 10 https вызовов, время работы апи вконтакта от 6 ms до 100 ms к примеру. Еще количество запросов в секунду к апи соц сети ограничено. Т.е. пока я рассылаю нотификейшены для первых 100к прользователей среди них логинится десять. В результате я 10-и пользователям могу отправить по 2 нотификейшена (так как результаты поиска сдвигаются). В альтернативном варианте я могу выполнять SQL без дат, а даты обрабатывать в коде сервера (сейчас у меня так сделано). В этом случае проблем нет с отправкой, но с обновлением следующая:

В ответах api соц сети получаю id получивших. Это новый список (только часть из тех, кому пытался отправить). Вот их надо обновить, не всех в диапазоне min_id ... max_id. Отсюда IN и вопрос что лучше, 10 запросов по 100 или 1 на 1000. (1000 это в худшем случае, обычно меньше, т.к. многие пользователи отключают нотификейшены).
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 03.09.2015, 23:19   #8
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Сообщение от pax Посмотреть сообщение
Ух, ну и спор начался...
Да жесть вообще


Сообщение от pax Посмотреть сообщение
Запрос примерно такого плана:
"SELECT * 
FROM users 
WHERE id > @last_largest_id AND sn = 'vk' AND DATE_ADD(last_login, INTERVAL 31 day) > NOW() 
ORDER BY id 
LIMIT 1000" 
Заместо использования offset, используй самый большой ID пользователя с последнего списка пользователей. Изначально 0.
Тогда не будет никто влезать если залогинятся.

Сообщение от pax Посмотреть сообщение
В ответах api соц сети получаю id получивших. Это новый список (только часть из тех, кому пытался отправить). Вот их надо обновить, не всех в диапазоне min_id ... max_id. Отсюда IN и вопрос что лучше, 10 запросов по 100 или 1 на 1000. (1000 это в худшем случае, обычно меньше, т.к. многие пользователи отключают нотификейшены).
Тут, UPDATE c id IN будет "ок", можешь смело делать на каждый ответ с api соц сети.

Если смотреть проще, можешь даже делать по одному запросу на LIMIT 100, обрабатывать его в другом потоке.
Далее если у тебя по времени влезает в ограничения соц. сети, то делаешь еще запрос, и так по кругу, пока не будешь упираться в ограничения по времени.
Таким образом можно будет и паралельно пачками слать, в итоге у тебя будет максимальная скорость рассылки. Т.к. работа с бд у тебя будет по любому в разы быстрее чем их ограничения на api.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
pax (04.09.2015)
Старый 04.09.2015, 00:23   #9
Randomize
Терабайт исходников
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: Планета Земля
Сообщений: 4,061
Написано 2,280 полезных сообщений
(для 6,374 пользователей)
Ответ: [MySql] Оператор сравнения IN

Pax, я повторюсь, используй EXPLAIN для профилирования запросов.
Там наглядно показано как что на производительность влияет.
А то тут уже непонятные споры на ровном месте.
__________________
Retry, Abort, Ignore? █
Пека: AMD Athlon II x4 2.6Ghz; 8Gb ram; Nvidia Geforce GTX 750 Ti
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо Randomize за это полезное сообщение:
moka (04.09.2015), pax (04.09.2015)
Старый 04.09.2015, 07:47   #10
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
Ответ: [MySql] Оператор сравнения IN

Сообщение от moka Посмотреть сообщение
Заместо использования offset, используй самый большой ID пользователя с последнего списка пользователей. Изначально 0.
Тогда не будет никто влезать если залогинятся.
Теперь понял, спасибо!
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
moka (04.09.2015)
Старый 06.09.2015, 00:11   #11
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Вынес оффтоп сюда: http://forum.boolean.name/showthread.php?t=19986

pax, было бы интересно если ты использовал бы EXPLAIN на все запросы твоего скрипта. И вообще поделился бы в итоге результатами скорости работы SQL запросов, размера таблицы и времени работы всего скрипта на одну рассылку по всем пользователям.
(Offline)
 
Ответить с цитированием
Старый 06.09.2015, 14:36   #12
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
Ответ: [MySql] Оператор сравнения IN

Это было бы круто, но тестировать на живую сложно. Пока нотификейшен сервер не обновлен в игре и рассылать уведомления просто так не хороший тон. Делать фейковую базу для тестирования нагрузки просто нет времени.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 07.09.2015, 00:38   #13
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Ну ты замерь время выполнения реального скрипта, и кинь в логи, потом поделись данным.
Имхо как разработчик ты же сам должен знать сколько занимают твои скрипты, иначе это слепо надеятся на то что оно как-то работает нормально?
(Offline)
 
Ответить с цитированием
Старый 07.09.2015, 07:50   #14
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,490
Написано 2,950 полезных сообщений
(для 5,205 пользователей)
Ответ: [MySql] Оператор сравнения IN

Когда-нибудь заморочусь над этим. Одно могу сказать точно, при вчерашнем обновлении игры рассылка нотификейшенов прошла быстрее. Но там был комплекс переработок. Нагрузка на БД уменьшилась во время рассылки (чего я и хотел добиться). Вероятно из-за выборки по последнему разосланному id пользователя и выборке по 1000 вместо 100. Нагрузка на CPU увеличилась, но с этим мне еще предстоит разобраться. Полное логирование времени запросов лень делать чисто потому, что нотификейшены мы массово рассылаем раз в неделю две.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 07.09.2015, 10:57   #15
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,423
Написано 3,449 полезных сообщений
(для 6,840 пользователей)
Ответ: [MySql] Оператор сравнения IN

Но предположим рассылка нотификейшенов занимает 5 минут всего.
Где 2 минуты расходуются на обработку SQL запросов. Это пару раз в неделю, вы будете на этот период сильно снижать производительность других сложных и менее сложных запросов. На 2 минуты ответы от бд будут дольше, это в сценарии если бд юзает очень много CPU и/или IO. Вот и будет неприятно на 2 минуты могут быть лаги.
(Offline)
 
Ответить с цитированием
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +1, время: 14:41.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com