|
|
Знаете ли Вы, что ... | |
![]() |
...до того как открыть новую тему, стоит использовать поиск: такая тема уже может существовать. |
<< Предыдущий совет - Случайный совет - Следующий совет >> |
Разное/IT Всё, что не попадает в другие разделы форума и подфорумов представленных здесь организаций. Не IT темы обсуждаются в "Беседке" |
Ответить |
|
Опции темы | Опции просмотра |
|
![]() |
#1 | |
![]() Google
software engineer
AKA:Y combinator
Сообщений: 418
+ 114
374/183
– 6
9/8
![]() |
Цитата:
Поднял для экспериментов облачный сервер на selectel.ru: 8 GB RAM, 8 потоков (Xeon E5-2630@2.3 GHz), Debian 7 amd64, MySQL 5.5.31. В my.cnf поправил следующее: Код:
key_buffer_size = 128M sort_buffer_size = 64M query_cache_limit = 4M query_cache_size = 512M innodb_file_per_table innodb_buffer_pool_size = 4G innodb_log_file_size = 512M Код:
SELECT * FROM test ORDER BY RAND() LIMIT 10; Попробовал помочь планировщику, чтобы не сортировал строки целиком: Код:
SELECT test.* FROM test JOIN (SELECT id FROM test ORDER BY RAND() LIMIT 10) sub ON test.id = sub.id; Погасил MySQL, поднял PostgreSQL. Версия 9.1.9, в конфиге поправил только: Код:
shared_buffers = 4G work_mem = 64M maintenance_work_mem = 64MB Код:
SELECT * FROM test ORDER BY random() LIMIT 10; Код:
SELECT test.* FROM test JOIN (SELECT id FROM test ORDER BY random() LIMIT 10) sub ON test.id = sub.id; Кто интересовался, чем постгрес лучше — в частности вот. Причину колоссального отрыва на первом запросе легко выяснить в плане: Код:
QUERY PLAN ----------- Limit (cost=308654.61..308654.63 rows=10 width=1060) (actual time=2989.145..2989.171 rows=10 loops=1) -> Sort (cost=308654.61..311154.60 rows=999999 width=1060) (actual time=2989.141..2989.150 rows=10 loops=1) Sort Key: (random()) Sort Method: top-N heapsort Memory: 38kB -> Seq Scan on test (cost=0.00..287044.99 rows=999999 width=1060) (actual time=81.551..1435.582 rows=999999 loops=1) При достаточно равномерном распределении автоинкрементного ключа способ с выборкой N случайных ID в диапазоне min..max, наверное, самый практичный. Если с ключом проблемы, а запросы на N случайных записей ну очень важны, я бы попробовал материализовать это так: Код:
ALTER TABLE test ADD COLUMN rndkey double precision NOT NULL DEFAULT random(); CREATE INDEX test_rndkey ON test(rndkey); Код:
SELECT * FROM test WHERE rndkey > random() ORDER BY rndkey LIMIT 1; Цена такого запроса — один проход по хорошо сбалансированному индексу. На «горячих» данных — единицы миллисекунд в любой базе. Запрос с некоторой вероятностью может не вернуть данных вообще, поэтому его нужно повторять, пока не наберётся N строк. Все равно дешевле, чем full scan. Для минимизации накладных расходов по общению с базой можно завернуть в хранимку. Самый эффективный способ, пожалуй, должен быть реализован напрямую в базе, как TABLESAMPLE в SQL Server: имея карту данных на диске, выбрать некоторое количество случайных страниц указанной таблицы, и вытянуть строки оттуда — минуя индексы и всё остальное. |
|
|
Ответить |
7 "+" от:
|
![]() |
#2 | |
Сообщений: 3,327
+ 337
892/590
– 3
31/25
![]() |
Цитата:
Думаю Rooslan Khayrov знает об этом, и мое сообщение не ему адресовано. ;-)
__________________
404 Not Found |
|
|
Ответить |
|