Eu tenho uma tabela no postgres que contém alguns milhões de linhas. Eu verifiquei na internet e encontrei o seguinte
SELECT myid FROM mytable ORDER BY RANDOM() LIMIT 1;
Funciona, mas é muito lento ... existe outra forma de fazer essa consulta, ou uma forma direta de selecionar uma linha aleatória sem ler toda a tabela? A propósito, 'myid' é um número inteiro, mas pode ser um campo vazio.
postgresql
random-access
Juan
fonte
fonte
Respostas:
Você pode querer experimentar
OFFSET
, como emSELECT myid FROM mytable OFFSET floor(random()*N) LIMIT 1;
O
N
é o número de linhas emmytable
. Você pode precisar primeiro fazer umSELECT COUNT(*)
para descobrir o valor deN
.Atualizar (por Antony Hatchkins)
Você deve usar
floor
aqui:Considere uma tabela de 2 linhas;
random()*N
gera0 <= x < 2
e, por exemplo,SELECT myid FROM mytable OFFSET 1.7 LIMIT 1;
retorna 0 linhas devido ao arredondamento implícito para o int mais próximo.fonte
SELECT COUNT(*)
?, quer dizer, não usar todos os valores da tabela, mas apenas uma parte deles?EXPLAIN SELECT ...
com valores diferentes de N dá o mesmo custo para a consulta, então eu acho que é melhor ir para o valor máximo de N.PostgreSQL 9.5 introduziu uma nova abordagem para seleção de amostra muito mais rápida: TABLESAMPLE
A sintaxe é
Esta não é a solução ideal se você deseja apenas uma linha selecionada, porque você precisa saber a CONTAGEM da tabela para calcular a porcentagem exata.
Para evitar um COUNT lento e usar TABLESAMPLE rápido para tabelas de 1 linha a bilhões de linhas, você pode fazer:
Isso pode não parecer tão elegante, mas provavelmente é mais rápido do que qualquer uma das outras respostas.
Para decidir se deseja usar o BERNULLI oder SYSTEM, leia sobre a diferença em http://blog.2ndquadrant.com/tablesample-in-postgresql-9-5-2/
fonte
SELECT * FROM my_table TABLESAMPLE SYSTEM(SELECT 1/COUNT(*) FROM my_table) LIMIT 1;
?SELECT reltuples FROM pg_class WHERE relname = 'my_table'
para estimativa de contagem.Eu tentei isso com uma subconsulta e funcionou bem. O deslocamento, pelo menos no Postgresql v8.4.4, funciona bem.
fonte
Você precisa usar
floor
:fonte
random()*N
gera 0 <= x <2 e, por exemplo,SELECT myid FROM mytable OFFSET 1.7 LIMIT 1;
retorna 0 linhas devido ao arredondamento implícito para o int mais próximo.order by random()
, aproximadamente como3*O(N) < O(NlogN)
- os números da vida real serão ligeiramente diferentes devido aos índices.WHERE myid NOT IN (1st-myid)
eWHERE myid NOT IN (1st-myid, 2nd-myid)
não funcionariam já que a decisão é feita pelo OFFSET. Hmmm ... acho que poderia reduzir N em 1 e 2 no segundo e no terceiro SELECT.floor()
? Que vantagem isso oferece?Verifique este link para algumas opções diferentes. http://www.depesz.com/index.php/2007/09/16/my-thoughts-on-getting-random-row/
Atualizar: (A. Hatchkins)
O resumo do (muito) longo artigo é o seguinte.
O autor lista quatro abordagens:
1)
ORDER BY random() LIMIT 1;
- lento2)
ORDER BY id where id>=random()*N LIMIT 1
- não uniforme se houver lacunas3) coluna aleatória - precisa ser atualizada de vez em quando
4) agregado aleatório personalizado - método astuto, pode ser lento: random () precisa ser gerado N vezes
e sugere melhorar o método 2 usando
5)
ORDER BY id where id=random()*N LIMIT 1
com repetições subsequentes se o resultado estiver vazio.fonte
A maneira mais fácil e rápida de buscar linha aleatória é usar a
tsm_system_rows
extensão:Em seguida, você pode selecionar o número exato de linhas que deseja:
Isso está disponível com PostgreSQL 9.5 e posterior.
Veja: https://www.postgresql.org/docs/current/static/tsm-system-rows.html
fonte
ORDER BY random() LIMIT 1;
deve ser rápido o suficiente.Eu vim com uma solução muito rápida sem
TABLESAMPLE
. Muito mais rápido do queOFFSET random()*N LIMIT 1
. Nem mesmo requer contagem de mesa.A ideia é criar um índice de expressão com dados aleatórios, mas previsíveis, por exemplo
md5(primary key)
.Aqui está um teste com dados de amostra de 1 milhão de linhas:
Resultado:
Esta consulta pode às vezes (com probabilidade de cerca de 1 / Número_de_rows) retornar 0 linhas, então ela precisa ser verificada e executada novamente. Além disso, as probabilidades não são exatamente as mesmas - algumas linhas são mais prováveis do que outras.
Para comparação:
Os resultados variam muito, mas podem ser muito ruins:
fonte