Como faço para obter uma amostra aleatória simples eficiente no SQL? O banco de dados em questão está executando MySQL; minha tabela tem pelo menos 200.000 linhas e quero uma amostra aleatória simples de cerca de 10.000.
A resposta "óbvia" é:
SELECT * FROM table ORDER BY RAND() LIMIT 10000
Para tabelas grandes, isso é muito lento: ele chama RAND()
cada linha (o que já o coloca em O (n)) e os classifica, tornando-o O (n lg n) na melhor das hipóteses. Existe uma maneira de fazer isso mais rápido do que O (n)?
Nota : Como Andrew Mao aponta nos comentários, se você estiver usando essa abordagem no SQL Server, deve usar a função T-SQL NEWID()
, porque RAND () pode retornar o mesmo valor para todas as linhas .
EDITAR: 5 ANOS DEPOIS
Eu me deparei com esse problema novamente com uma mesa maior e acabei usando uma versão da solução do @inognant, com dois ajustes:
- Amostrar as linhas de 2 a 5x o tamanho de amostra desejado, a baixo custo
ORDER BY RAND()
- Salve o resultado de
RAND()
em uma coluna indexada em cada inserção / atualização. (Se o seu conjunto de dados não for muito atualizado, pode ser necessário encontrar outra maneira de manter esta coluna atualizada.)
Para obter uma amostra de 1000 itens de uma tabela, conto as linhas e faço uma amostra do resultado até, em média, 10.000 linhas com a coluna frozen_rand:
SELECT COUNT(*) FROM table; -- Use this to determine rand_low and rand_high
SELECT *
FROM table
WHERE frozen_rand BETWEEN %(rand_low)s AND %(rand_high)s
ORDER BY RAND() LIMIT 1000
(Minha implementação real envolve mais trabalho para garantir que eu não subamostra, e para envolver manualmente rand_high, mas a ideia básica é "cortar aleatoriamente seu N para alguns milhares.")
Embora isso faça alguns sacrifícios, me permite analisar o banco de dados usando uma varredura de índice, até que esteja pequeno o suficiente para ORDER BY RAND()
novamente.
RAND()
retorna o mesmo valor a cada chamada subsequente.