Такая же история ;) И класс sfSphinxClient толком наследовать не получается, потому как private $res, а чужой код мы стараемся не изменять ;)
С вашей версией обёртки ознакомиться где-нибудь можно?
EXPLAIN SELECT * FROM `a` WHERE `f` = число ORDER BY RAND() LIMIT 10;
здесь ORDER BY RAND() происходит только среди 164 рядов (всего было 163712),
от лишних мы избавились с помошью WHERE на индексированной колонке. В этом и есть основная мысль этого поста.
На всё той же своей таблице тестирую метод TimTowdy, тот же комп, те же мощности софт- и хардвара.
SELECT r1.`id`, `md5`
FROM a AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(`id`) FROM `a`)) AS `id`
) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1; -> (1 rows total, Query took 0.0318 sec)
Таких выборок должно быть 10. Проверив выборку через EXPLAIN SELECT узнаю что скан идёт по 15000 рядам. Мда, ну ладно пусть так. Думается, что быстрее всего получится запустить это 10 раз одной командой, объединяя результат командой UNION. Возможны другие способы, увы, в голову не приходят (если что кидайте, проверим). Итак:
(SELECT r1.`id`, `md5` FROM a AS r1 JOIN
(SELECT (RAND() * (SELECT MAX(`id`) FROM `a`)) AS `id` ) AS r2
WHERE r1.id >= r2.id ORDER BY r1.id ASC LIMIT 1)
UNION (SELECT r1.`id`, `md5` FROM a AS ... и так 10 раз подряд-> (10 rows total, Query took 0.3303 sec)
Вызов полученного много-много раз дал самое быстрое — 0.0959 sec, среднее 0.2900. О качестве рандома судить сложно… Испробовал что будет если удалить из середины большой кусок записей и вставить их, например, в конец таблицы…
DELETE FROM `a` WHERE `id` > 1000 LIMIT 3000;
INSERT INTO `a` (md5) SELECT md5 FROM `a` LIMIT 3000;
Случайные выборки по-прежнему от 0.3 до 0.1 секунды.
Теперь самое интересное — удваиваю оъём таблицы.
INSERT INTO `a` (md5) SELECT md5 FROM `a`;
UPDATE `a` SET md5 = MD5(`id`), f = RAND()*2000;
Сначала с f-индексом, затем методом TimTowdy:
SET @rnd = RAND()*2000;
SELECT * FROM `a` WHERE `f` = @rnd ORDER BY RAND() LIMIT 10; -> 0.0021 sec - 0.0023 sec - 0.0133 sec
(SELECT r1.`id`, `md5` FROM a AS r1 JOIN
(SELECT (RAND() * (SELECT MAX(`id`) FROM `a`)) AS `id` ) AS r2
WHERE r1.id >= r2.id ORDER BY r1.id ASC LIMIT 1)
UNION (SELECT r1.`id`, `md5` FROM a AS ... -> 0.0927 sec - 0.1218 sec - 0.3964 sec.
Согласен, неплохой результат для выборки без лишней колонки и лишнего индекса. Экономным must use, а тем кто предпочитает иметь скорость и контролировать её понравится индекс. Я понимаю что у всех нас разные требования к приложениям, от этого и количество вариантов и я лично за! За то, чтобы усовершенствование продолжалось, чтобы мысль в эту сторону направлена была, чтобы мы не забывали полюбившуюся нам базу данных и учились для себя из неё-родимой выжимать максимум )
Имеется 1000 (максимальный f) абсолютно непересекающихся «рандомов» которые в свою очередь перетасовываются ORDER BY RAND(), а из полученного уже берётся 10 верхних записей. Если перегенеривать значения колонки f каждые, скажем 1000 запросов… или 100… то где здесь псевдослучайность? ;) Если вам не нравится функция RAND() можете использовать посложнее:
UPDATE `a` SET `f` = HEX(MID(MD5(RAND()),3,2)); -> 163072 row(s) affected. ( Query took 4.5446 sec )
Проверяем качество разброса:
SELECT `f`, COUNT(1) C FROM `a` GROUP BY `f` LIMIT 10; ->
Имеем примерно по 650 записей на каждый f, всего 255 вариантов f. Для быборок будет чуть сложнее генерить f, но псевдослучайность мы убили, думается, на корню ;)
SET @rnd = HEX(MID(MD5(RAND()),3,2));
SELECT * FROM `a` WHERE `f` = @rnd ORDER BY RAND() LIMIT 10;
Значение f — это не критерий поиска, это всего лишь ускорение прохода по таблице. Смысл не в том, чтобы выбрать из различных f ;))) Хотя да, эсли внезапно понадобилось более 10 случайных результатов, а индекс перестраивать не хочется, то подойдёт такой вариант: SELECT * FROM `a` WHERE `f` IN (100,500,x5,x25,... ) ORDER BY RAND() LIMIT 10;
Класная идея купить такие часики. Попробую найти где в нашей месности можно их приобрести. Спасибо автору статьи.
Представляю как удивлённые владельцы всяческих часовых магазинов чешу репят — чего это все на шахматные часы так налетели? ;)
Можно поменять например на youtu.be/K40_xSpRREM или youtu.be/Ix55rt97PwU
Мне обещали позвонить и не позвонили.
— Сколько я допустил здесь опечаток?
По-моему с методом in всё в порядке, возвращает Symfony\Components\Finder
С вашей версией обёртки ознакомиться где-нибудь можно?
EXPLAIN SELECT * FROM `a` WHERE `f` = число ORDER BY RAND() LIMIT 10;
здесь ORDER BY RAND() происходит только среди 164 рядов (всего было 163712),
от лишних мы избавились с помошью WHERE на индексированной колонке. В этом и есть основная мысль этого поста.
EXPLAIN SELECT * FROM `test` LIMIT 1 OFFSET 1234
И даже это звучит как-то не внушительно:
EXPLAIN SELECT `id` FROM `test` LIMIT 1 OFFSET 1234
Но за ваш вариант спасибо… )
Ну да, для получения одного приходится жертвовать другим…
Таких выборок должно быть 10. Проверив выборку через EXPLAIN SELECT узнаю что скан идёт по 15000 рядам. Мда, ну ладно пусть так. Думается, что быстрее всего получится запустить это 10 раз одной командой, объединяя результат командой UNION. Возможны другие способы, увы, в голову не приходят (если что кидайте, проверим). Итак:
Вызов полученного много-много раз дал самое быстрое — 0.0959 sec, среднее 0.2900. О качестве рандома судить сложно… Испробовал что будет если удалить из середины большой кусок записей и вставить их, например, в конец таблицы…
Случайные выборки по-прежнему от 0.3 до 0.1 секунды.
Теперь самое интересное — удваиваю оъём таблицы. Сначала с f-индексом, затем методом TimTowdy: Согласен, неплохой результат для выборки без лишней колонки и лишнего индекса. Экономным must use, а тем кто предпочитает иметь скорость и контролировать её понравится индекс. Я понимаю что у всех нас разные требования к приложениям, от этого и количество вариантов и я лично за! За то, чтобы усовершенствование продолжалось, чтобы мысль в эту сторону направлена была, чтобы мы не забывали полюбившуюся нам базу данных и учились для себя из неё-родимой выжимать максимум )
Проверяем качество разброса:
Имеем примерно по 650 записей на каждый f, всего 255 вариантов f. Для быборок будет чуть сложнее генерить f, но псевдослучайность мы убили, думается, на корню ;)
SELECT * FROM `a` WHERE `f` IN (100,500,x5,x25,... ) ORDER BY RAND() LIMIT 10;
Представляю как удивлённые владельцы всяческих часовых магазинов чешу репят — чего это все на шахматные часы так налетели? ;)