С нами с 01.04.07
Сообщения: 4378
Рейтинг: 2970
|
Добавлено: 29/03/09 в 19:13 |
Подскажите пожалуйста.
Есть таблица, допустим, на 100.000 записей. Нужно делать простенький рандом с одним-двумя условиями where. Допустим, в пиковые моменты будет делаться до 100 запросов в секунду.
Как лучше организовать?
Либо стандартный " ORDER BY RAND LIMIT 1", либо через "count" - рандом средствами пхп? Может ещё какие варианты.
Спасибо.
|
|
|
|
« ... full on ... »
С нами с 17.03.07
Сообщения: 670
Рейтинг: 1686
|
Добавлено: 29/03/09 в 20:17 |
ORDER BY RAND() довольно тормознутый, особенно на больших таблицах. А если ещё 100 запросов в секунду - вполне может подвесить базу.
Как вариант (если есть ID), сделать "кучу" и хранить в ней список битых ID (т.е. тех записей, которые были удалены из последовательности 1-100000). Если нет битых ID, т.е. записи чётко по порядку, то просто хранить максимальное значение ID (last id).
И далее на PHP в цикле формировать случайный список ID с исключениями "битых" (это вопрос уже чисто технический), а потом делать выборку через SELECT ... WHERE ID IN (23,565,9232,23843)... и т.д. Это значительно снизит нагрузку, особенно при таком большом кол-ве запросов в секунду.
А "кучу" и LAST ID (или тот же результат count()) лучше хранить вне базы.
|
|
Power of the lime madness...
|
5
|
|
|
ищу работу (php,mysql,js)
С нами с 26.05.07
Сообщения: 576
Рейтинг: 393
|
Добавлено: 29/03/09 в 20:25 |
потёрто
|
|
|
|
С нами с 01.04.07
Сообщения: 4378
Рейтинг: 2970
|
Добавлено: 29/03/09 в 20:28 |
Corex: возможно, неправильно объяснил. Имел в виду - 100 обращений к скрипту, рандом должен выбирать только одно значение.
|
|
|
|
www.phpdevs.com
С нами с 24.10.02
Сообщения: 16633
Рейтинг: 16105
|
Добавлено: 29/03/09 в 20:31 |
а надо ли каждый раз рандом ? Может достаточно раз в минуту рандом дергать, а остальное время скешированный вариант брать.
|
|
Пишу на php/mysql/django за вменяемые деньги.
Обращаться в личку.
|
5
|
|
|
С нами с 01.04.07
Сообщения: 4378
Рейтинг: 2970
|
Добавлено: 29/03/09 в 20:36 |
Надо
Задача скрипта - кидать пользователя на случайный адрес. То есть, как out в сиджеях, ТДС и некоторых топлистах.
|
|
|
|
ищу работу (php,mysql,js)
С нами с 26.05.07
Сообщения: 576
Рейтинг: 393
|
Добавлено: 29/03/09 в 20:39 |
от задачи и от структуры данных зависит, можно и так и так...
можно создать дополнительную таблицу с заранее отобраными рандомными значениями (в 10 раз меньше основной), брать значения из дополнительной таблицы, раз в час дополнительную таблицу обновлять
многое зависит от условия WHERE (если по ключу - то запрос будет быстрее работать, чем если %LIKE% ...)
имхо - мускуль с оптимизироваными таблицами/запросами
|
|
|
|
С нами с 01.04.07
Сообщения: 4378
Рейтинг: 2970
|
Добавлено: 29/03/09 в 20:44 |
Условие простое, никаких like
|
|
|
|
Чингачгук, вождь красноглазых
С нами с 14.05.04
Сообщения: 4744
Рейтинг: 1824
|
Добавлено: 29/03/09 в 21:35 |
Вообще-то, 100.000 записей IP-адресов - это всего лишь 400.000 байтов данных на C или Java, даже не смешно. Самый быстрый вариант - это вообще отказаться от PHP (поскольку оно не может перманентно в памяти что-то держать), написать эту хренобень на Java, держа все данные в памяти аппликейшн-сервера со старта приложения, и хреначить просто по случайному индексу из массива, будет лупить как пулемет при любом количестве запросов в секунду
C php тоже можно решение найти, типа класть это все в DBM и кэшировать в shared memory -не так просто и элегантно, конечно, и вероятность багов поймать больше. Но полюбэ лучше, чем к базе лезть каждый раз - ибо рандомные выборки на таблице в 100.000 записей 100 раз в секунду вообще нехило нагрузят сервак. Немножко не того масштаба задача, имхо, чтобы ее в лоб решать.
|
|
|
|
С нами с 01.04.07
Сообщения: 4378
Рейтинг: 2970
|
Добавлено: 29/03/09 в 22:07 |
Цитата: | DBM и кэшировать в shared memory |
Я слов-то таких не знаю
Поэтому, предпочёл бы решения в пределах пхп+mysql
|
|
|
|
www.phpdevs.com
С нами с 24.10.02
Сообщения: 16633
Рейтинг: 16105
|
Добавлено: 30/03/09 в 00:52 |
<?php
$rand = rand(0,100000);
$sql = "SELECT * FROM table LIMIT ".$rand.',1';
?>
Ну как то так можно извернуться Число для рандома можно тупо кроном определять. В общем уже дальше от задачи зависит.
|
|
Пишу на php/mysql/django за вменяемые деньги.
Обращаться в личку.
|
5
|
|
|
Чингачгук, вождь красноглазых
С нами с 14.05.04
Сообщения: 4744
Рейтинг: 1824
|
Добавлено: 30/03/09 в 03:01 |
Stek писал: | <?php
$rand = rand(0,100000);
$sql = "SELECT * FROM table LIMIT ".$rand.',1';
?>
|
Ух.. а это не приведет ли к тому, что MySQL сделает сначала $rand SELECT'ов, тупо перебирая ряды и вернет только 1 из них? Имхо offset в LIMIT так и работает. Это уж базу убьет наповал точно.
gimcnuk писал: |
Поэтому, предпочёл бы решения в пределах пхп+mysql
|
..Ну и будет работать оно соответственно.
Не удивляет, что игры на php+mysql не пишут? ;)
В любом случае в подобной ситуации "1 запрос = 1 SELECT" будет смертью неминучей и какое-то кэширование предусматривать надо. Держать какие-то результаты в таблице, размещенной в памяти и выбирать из них (есть у MySQL и такое). Типа выбираем в нее 1000 рядов, 10 секунд раздаем из нее, потом переписываем, дальше работаем. Но только не 100.000 рядов по 100 запросов/сек на MyISAM, упаси боже.
|
|
|
|
С нами с 01.04.07
Сообщения: 4378
Рейтинг: 2970
|
Добавлено: 30/03/09 в 07:34 |
Всем спасибо.
Stek: ну я про такой вариант и спрашивал в первом сообщении, как лучше-то: random средствами mysql или php
Dr.Syshalt: предложенные условия теоретические, в реальности всё будет меньше. Поэтому и не хочу выходить за пределы php+mysql. Не тот уровень.
|
|
|
|
С нами с 15.01.08
Сообщения: 79
Рейтинг: 48
|
Добавлено: 30/03/09 в 09:54 |
рандом из mysql это жопа. по любому жопа...
я в свое время решил так
раз в минуту по крону выгружал из базы данные в текстовый файл, а потом из пхп
$tmp = file('base.txt');
shuffle($tmp);
echo $tmp[0];
|
|
|
|
« ... full on ... »
С нами с 17.03.07
Сообщения: 670
Рейтинг: 1686
|
Добавлено: 30/03/09 в 09:58 |
gimcnuk
Выборка по конкретному ID тогда более оптимальный вариант, т.к. будет работать значительно быстрее. + на ID сделать индексы. Это, конечно, если есть ID. Dr.Syshalt правильно написал про промежуточный вариант на 10 секунд - при большой нагрузке это поможет.
DMV_
Грузить в память 100К записей не лучший вариант, это не даст выиграша в скорости. А если это делать в несколько потоков 100 раз в секунду и каждый раз читать с диска файл в несколько Мб. - будут те же тормоза, если вообще всё не сдохнет.
|
|
Power of the lime madness...
|
5
|
|
|
С нами с 15.01.08
Сообщения: 79
Рейтинг: 48
|
Добавлено: 30/03/09 в 10:24 |
Corex: недописал слово рандомно
раз в минуту по крону выгружал из базы РАНДОМНО данные в текстовый файл, а потом из пхп
то есть выгружаешь например 1000 записей раз в минуту.
|
|
|
|
С нами с 01.02.07
Сообщения: 231
Рейтинг: 294
|
Добавлено: 30/03/09 в 12:58 |
Stek писал: | <?php
$rand = rand(0,100000);
$sql = "SELECT * FROM table LIMIT ".$rand.',1';
?>
Ну как то так можно извернуться Число для рандома можно тупо кроном определять. В общем уже дальше от задачи зависит. |
Абсолютно правильное решение, только вместо 100000 желательно подставлять реальное кол-во записей (если оно меняется):
SELECT count(*) FROM table;
ЗЫ: Запрос полностью идентичен следующему (просто синтаксис сокращенный):
SELECT * FROM table LIMIT 1 OFFSET $rand;
который работает очень быстро.
|
|
|
|
www.phpdevs.com
С нами с 24.10.02
Сообщения: 16633
Рейтинг: 16105
|
Добавлено: 30/03/09 в 13:12 |
Цитата: | Абсолютно правильное решение, только вместо 100000 желательно подставлять реальное кол-во записей (если оно меняется):
SELECT count(*) FROM table; |
Просто $rand вообще может тупо из файла браться, куда оно кроном раз в минуту пишется. Тогда в скрипте остается только один запрос в базу.
В общем и говорю, что проще создать таблицу на 100к записей и прогнать тестом разные варианты. Там дело то на 20 минут
|
|
Пишу на php/mysql/django за вменяемые деньги.
Обращаться в личку.
|
5
|
|
|
Чингачгук, вождь красноглазых
С нами с 14.05.04
Сообщения: 4744
Рейтинг: 1824
|
Добавлено: 30/03/09 в 13:21 |
zuborg писал: |
ЗЫ: Запрос полностью идентичен следующему (просто синтаксис сокращенный):
SELECT * FROM table LIMIT 1 OFFSET $rand;
который работает очень быстро. |
Серьезно?
Цитата: |
SELECT ... LIMIT offset, limit, where offset is a large number == bad, at least with InnoDB tables, as MySQL actually counts out every record until it gets to the offset.
|
Отсюда. Но на самом деле, запрос на Гугле "mysql select limit offset performance" выдаст много чего интересного. А можно просто дать себе труд подумать над тем, как может работать реализация "limit/offset" - и все понятно уже.
|
|
|
|
Чингачгук, вождь красноглазых
С нами с 14.05.04
Сообщения: 4744
Рейтинг: 1824
|
Добавлено: 30/03/09 в 13:39 |
Вообще из того, как работает random на MySQL, самый быстрый рандомный запрос - это рандом по первичному ключу, где только он извлекается из таблицы. И вот тут человек уже боролся с подобной проблемой. Интересное для ТС решение - последнее:
Код: |
SELECT * FROM Table T JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Table) AS x ON T.ID >= x.ID LIMIT 1;
|
Боюсь, средствами MySQL быстрее рандомной выборки не сделать. Как я уже сказал, более глобальное решение - это перманентный кэш в памяти (что, с использованием только PHP, возможно лишь средствами Zend Platform, иначе надо быть программером уровня, который найти на Master-X будет нелегко, такой тут вообще один... шутка), или, что то же самое - некий демон на том же перле, который в памяти сидит постоянно и выдает эти случайные данные - только так.
|
|
|
|