Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
`f` = x заменить на `f` >= x, тогда по идее выборок менее чем с десятью элементами станет меньше.mysql> EXPLAIN SELECT * FROM a WHERE id >= RAND()*(SELECT MAX(id) FROM a) LIMIT 1 \G;SELECT * FROM `a` WHERE `f` IN (100,500,x5,x25,... ) ORDER BY RAND() LIMIT 10;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;SELECT CONV(MID(MD5(RAND()),-2),16,10);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, а тем кто предпочитает иметь скорость и контролировать её понравится индекс. Я понимаю что у всех нас разные требования к приложениям, от этого и количество вариантов и я лично за! За то, чтобы усовершенствование продолжалось, чтобы мысль в эту сторону направлена была, чтобы мы не забывали полюбившуюся нам базу данных и учились для себя из неё-родимой выжимать максимум )EXPLAIN SELECT * FROM `test` LIMIT 1 OFFSET 1234EXPLAIN SELECT `id` FROM `test` LIMIT 1 OFFSET 1234
Ускоряем выборку произвольных записей MySQL