Eu costumava sempre fazer isso em php após os resultados da consulta de sql ... esta é provavelmente muito mais rápido para processamento conforme apêndice limite 1 da solução
-1 para confiar order by rand()ou equivalentes em todos os dbs: |. também mencionado aqui .
AD7six
20
Dez anos atrás, um cara disse que o uso ORDER BY RAND()é errado ...
Trejder
ORDER BY NEWID () parece ser notavelmente mais lento no SQL Server. Minha consulta se parece com: selecione as 1000 principais C.CustomerId, CL.LoginName do grupo C de associação interna LinkedAccount LA em C.CustomerId = LA.CustomerId associação interna CustomerLogin CL no grupo C.CustomerId = CL.CustomerId por C.CustomerId, CL. LoginName com contagem (*)> 1 pedido por NEWID () A remoção da linha "pedido por NEWID ()" retorna os resultados muito mais rapidamente.
Ben Power
3
Para SQLite, use a função RANDOM ().
Slam
10
Essas soluções não escalam. Eles são O(n)com nsendo o número de registros na tabela. Imagine que você tem 1 milhão de registros. Deseja realmente gerar 1 milhão de números aleatórios ou IDs exclusivos? Prefiro usar COUNT()e envolver isso em uma nova LIMITexpressão com um único número aleatório.
Christian Hujer
174
Soluções como Jeremies:
SELECT*FROMtableORDERBY RAND() LIMIT 1
funcionam, mas precisam de uma varredura seqüencial de toda a tabela (porque o valor aleatório associado a cada linha precisa ser calculado - para que seja possível determinar o menor), o que pode ser bastante lento para tabelas de tamanho médio. Minha recomendação seria usar algum tipo de coluna numérica indexada (muitas tabelas têm essas como chaves primárias) e depois escrever algo como:
SELECT*FROMtableWHERE num_value >= RAND()*(SELECT MAX (num_value )FROMtable)ORDERBY num_value LIMIT 1
Isso funciona em tempo logarítmico, independentemente do tamanho da tabela, se num_valueestiver indexado. Uma ressalva: isso assume que num_valueé igualmente distribuído no intervalo 0..MAX(num_value). Se o seu conjunto de dados se desviar fortemente dessa suposição, você obterá resultados distorcidos (algumas linhas aparecerão com mais frequência do que outras).
A segunda sugestão não é aleatória. Você não pode prever a linha que será escolhida, mas se tivesse que apostar, apostaria na segunda linha. E você nunca apostaria na última linha, é menos provável que seja escolhido, independentemente da distribuição do seu num_value e do tamanho da sua mesa.
Etienne Racine
1
Eu sei que geralmente as funções RAND () não são de alta qualidade, mas, além disso, você pode explicar por que a seleção não seria aleatória?
Grey Panther
13
O primeiro está errado no SQL Server. A função RAND () é invocada apenas uma vez por consulta, não uma vez por linha. Por isso, sempre seleciona a primeira linha (tente).
Jeff Walker Code Ranger
3
O segundo também assume que todas as linhas são contabilizadas: é possível escolher uma linha que foi excluída.
Sam Rueby
3
@ Sam.Rueby Na verdade, num_value> = RAND () ... o limite 1 garante que as linhas vazias sejam ignoradas até encontrar a linha existente.
Ghord
62
Não sei o quão eficiente isso é, mas já o usei antes:
SELECTTOP1*FROM MyTable ORDERBY newid()
Como os GUIDs são bastante aleatórios, a ordem significa que você obtém uma linha aleatória.
Estou usando o servidor MS SQL, SELECT TOP 1 * FROM some_table_name ORDER BY NEWID () funcionou muito bem para mim, obrigado pelo conselho pessoal!
Isso é exatamente a mesma coisa queORDER BY RAND() LIMIT 1
Ken Bloom
6
Isso também é muito específico do banco de dados, pois usa TOP 1e newid().
Cinza
12
Esta é uma má ideia. Este método não usará um índice, a menos que cada coluna seja indexada individualmente. A tabela com 100 milhões de registros pode levar muito tempo para obter um registro.
Interruptor
1
@Switch e que solução você proporia?
Akmal Salikhov
31
ORDERBY NEWID()
leva 7.4 milliseconds
WHERE num_value >= RAND()*(SELECT MAX(num_value)FROMtable)
A segunda opção não seleciona a última linha. Eu não sei por que - apenas apontando.
Voldemort
7
@Voldemort: rand()retorna um número de ponto flutuante em nque 0 < n < 1. Supondo que num_valueseja um número inteiro, o valor de retorno de rand() * max(num_value)também será coagido a um número inteiro, truncando qualquer coisa após o ponto decimal. Por isso, rand() * max(num_value)vai sempre ser inferior max(num_value), razão pela qual a última linha nunca será selecionado.
22615 Ian Kemp
Não serei eficiente se meus dados forem excluídos com frequência - se encontrar uma lacuna, terei que executar novamente a consulta inteira.
Loic Coenen
1
@IanKemp Pergunta estúpida, então por que não usar simplesmente SELECT MAX (num_value) + 1 ?? Como rand (ou RANDOM na maioria dos casos) retorna [0,1), você obtém toda a gama de valores. Além disso, sim, você está certo, precisa corrigir uma consulta.
tekHedd
13
Você não disse qual servidor está usando. Nas versões mais antigas do SQL Server, você pode usar isso:
selecttop1*from mytable orderby newid()
No SQL Server 2005 e superior, você pode usar TABLESAMPLEpara obter uma amostra aleatória que pode ser repetida:
SELECT FirstName, LastName
FROM Contact
TABLESAMPLE (1ROWS);
newid () / order by funcionará, mas será muito caro para grandes conjuntos de resultados porque ele precisa gerar um ID para cada linha e, em seguida, classificá-los.
TABLESAMPLE () é bom do ponto de vista de desempenho, mas você obterá agrupamentos de resultados (todas as linhas em uma página serão retornadas).
Para uma amostra aleatória verdadeira com melhor desempenho, a melhor maneira é filtrar as linhas aleatoriamente. Encontrei o seguinte exemplo de código no artigo Manuais Online do SQL Server Limitando os conjuntos de resultados usando o TABLESAMPLE :
Se você realmente deseja uma amostra aleatória de linhas individuais, modifique sua consulta para filtrar linhas aleatoriamente, em vez de usar TABLESAMPLE. Por exemplo, a consulta a seguir usa a função NEWID para retornar aproximadamente um por cento das linhas da tabela Sales.SalesOrderDetail:
A coluna SalesOrderID é incluída na expressão CHECKSUM para que NEWID () avalie uma vez por linha para obter amostragem por linha. A expressão CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) é avaliada como um valor flutuante aleatório entre 0 e 1.
Quando executado em uma tabela com 1.000.000 de linhas, eis meus resultados:
SETSTATISTICS TIME ONSETSTATISTICS IO ON/* newid()
rows returned: 10000
logical reads: 3359
CPU time: 3312 ms
elapsed time = 3359 ms
*/SELECTTOP1PERCENT Number
FROM Numbers
ORDERBY newid()/* TABLESAMPLE
rows returned: 9269 (varies)
logical reads: 32
CPU time: 0 ms
elapsed time: 5 ms
*/SELECT Number
FROM Numbers
TABLESAMPLE (1PERCENT)/* Filter
rows returned: 9994 (varies)
logical reads: 3359
CPU time: 641 ms
elapsed time: 627 ms
*/SELECT Number
FROM Numbers
WHERE0.01>= CAST(CHECKSUM(NEWID(), Number)&0x7fffffffAS float)/ CAST (0x7fffffffAS int)SETSTATISTICS IO OFFSETSTATISTICS TIME OFF
Se você conseguir usar o TABLESAMPLE, ele fornecerá o melhor desempenho. Caso contrário, use o método newid () / filter. newid () / order by deve ser o último recurso se você tiver um grande conjunto de resultados.
Se possível, use instruções armazenadas para evitar a ineficiência de ambos os índices no RND () e criar um campo de número de registro.
PREPARE RandomRecord FROM "SELECT * FROM tabela LIMIT?, 1";
SET @ n = FLOOR (RAND () * (SELECIONE CONTAGEM (*) DA tabela));
EXECUTE RandomRecord USING @n;
Essa solução também cuida do retorno de linhas aleatórias quando o valor numérico indexado usado na cláusula where acima não é distribuído igualmente; portanto, mesmo que leve quase o mesmo tempo (constante) do uso de onde id_value> = RAND () * MAX (id_value), é melhor.
guido
Tanto quanto posso dizer, isso não é executado em tempo constante, é executado em tempo linear. Na pior das hipóteses, @n é igual ao número de linhas da tabela e "SELECT * FROM table LIMIT?, 1" avalia as linhas @n - 1 até chegar à última.
Andres Riofrio
3
A melhor maneira é colocar um valor aleatório em uma nova coluna apenas para esse fim e usar algo como isto (código pseudo + SQL):
randomNo = random()
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo")
Esta é a solução empregada pelo código MediaWiki. Obviamente, existe algum viés em relação a valores menores, mas eles descobriram que era suficiente agrupar o valor aleatório em torno de zero quando nenhuma linha é buscada.
A solução newid () pode exigir uma varredura completa da tabela para que cada linha possa receber um novo guia, que terá muito menos desempenho.
A solução rand () pode não funcionar de todo (ou seja, com MSSQL) porque a função será avaliada apenas uma vez e a cada linha será atribuído o mesmo número "aleatório".
O agrupamento ao obter 0 resultado fornece uma amostra comprovadamente aleatória (não apenas "suficientemente boa"). Essa solução é quase escalável para consultas com várias linhas (pense em "reprodução aleatória"). O problema é que os resultados tendem a ser selecionados nos mesmos grupos repetidamente. Para contornar isso, você precisaria redistribuir os números aleatórios que você acabou de usar. Você pode trapacear mantendo o controle de randomNo e definindo-o como max (randomness) a partir dos resultados, mas depois p (linha i na consulta 1 E linha i na consulta 2) == 0, o que não é justo. Deixe-me fazer algumas contas e eu voltarei a você com um esquema realmente justo.
31410 alsuren
3
Para o SQL Server 2005 e 2008, se quisermos uma amostra aleatória de linhas individuais (dos Manuais Online ):
SELECT ID FROMTABLEWHERE ID >= My_Generated_Random ORDERBY ID LIMIT 1
Observe que ele verificará todas as linhas com IDs iguais ou superiores ao valor escolhido. Também é possível procurar a linha abaixo da tabela e obter um ID igual ou menor que o My_Generated_Random, e modificar a consulta da seguinte maneira:
SELECT ID FROMTABLEWHERE ID <= My_Generated_Random ORDERBY ID DESC LIMIT 1
O que aconteceria se o ID aleatório gerado não existir mais na tabela? Linhas excluídas ou passivas que você não deseja mostrar ao usuário podem causar problemas.
Ebleme
Nada. Você obtém o número de identificação mais próximo, não exato. Se você considerar id = 1 a ser removido, troque 1 pelo mínimo.
forsberg
2
Como apontado no comentário de @ BillKarwin na resposta de @ cnu ...
Ao combinar com um LIMIT, descobri que ele tem um desempenho muito melhor (pelo menos com o PostgreSQL 9.1) para JOIN com uma ordem aleatória em vez de ordenar diretamente as linhas reais: por exemplo
SELECT*FROM tbl_post AS t
JOIN...JOIN(SELECT id, CAST(-2147483648* RANDOM()AS integer)AS rand
FROM tbl_post
WHERE create_time >=1349928000) r ON r.id = t.id
WHERE create_time >=1349928000AND...ORDERBY r.rand
LIMIT 100
Apenas certifique-se de que o 'r' gere um valor de 'rand' para todos os possíveis valores de chave na consulta complexa associada a ele, mas ainda assim limite o número de linhas de 'r' sempre que possível.
O CAST como número inteiro é especialmente útil para o PostgreSQL 9.2, que possui otimização de classificação específica para tipos flutuantes de precisão inteira e única.
A maioria das soluções aqui visa evitar a classificação, mas elas ainda precisam fazer uma varredura seqüencial sobre uma tabela.
Também há uma maneira de evitar a varredura seqüencial alternando para a varredura de índice. Se você conhece o valor do índice da sua linha aleatória, pode obter o resultado quase instantaneamente. O problema é - como adivinhar um valor de índice.
A seguinte solução funciona no PostgreSQL 8.4:
explain analyze select*from cms_refs where rec_id in(select(random()*(select last_value from cms_refs_rec_id_seq))::bigint
from generate_series(1,10))
limit 1;
Acima da solução, você adivinha 10 valores de índice aleatórios diferentes do intervalo 0 .. [último valor do id].
O número 10 é arbitrário - você pode usar 100 ou 1000, pois (surpreendentemente) não tem um grande impacto no tempo de resposta.
Há também um problema - se você tiver identificações esparsas, poderá perder . A solução é ter um plano de backup :) Nesse caso, uma ordem antiga pura por consulta random (). Quando o ID combinado se parece com isso:
explain analyze select*from cms_refs where rec_id in(select(random()*(select last_value from cms_refs_rec_id_seq))::bigint
from generate_series(1,10))unionall(select*from cms_refs orderby random() limit 1)
limit 1;
Não é a cláusula ALL da união . Nesse caso, se a primeira parte retornar algum dado, a segunda NUNCA será executada!
No final, mas cheguei aqui pelo Google, então, por motivos de posteridade, adicionarei uma solução alternativa.
Outra abordagem é usar TOP duas vezes, com pedidos alternados. Não sei se é "SQL puro", porque usa uma variável no TOP, mas funciona no SQL Server 2008. Aqui está um exemplo que utilizo em uma tabela de palavras do dicionário, se quiser uma palavra aleatória.
SELECTTOP1
word
FROM(SELECTTOP(@idx)
word
FROM
dbo.DictionaryAbridged WITH(NOLOCK)ORDERBY
word DESC)AS D
ORDERBY
word ASC
Obviamente, @idx é um número inteiro gerado aleatoriamente que varia de 1 a COUNT (*) na tabela de destino, inclusive. Se sua coluna estiver indexada, você também será beneficiado. Outra vantagem é que você pode usá-lo em uma função, pois NEWID () não é permitido.
Por fim, a consulta acima é executada em cerca de 1/10 do tempo de execução de uma consulta do tipo NEWID () na mesma tabela. YYMV.
Depois de testar muitas das respostas, acredito que essa seja a melhor. Parece ser rápido e escolhe um bom número aleatório de cada vez. Parece semelhante à segunda sugestão de @GreyPanther acima, mas essa resposta seleciona mais números aleatórios.
Jeff Baker
1
Ainda não vi essa variação nas respostas. Eu tinha uma restrição adicional onde precisava, com base em uma semente inicial, para selecionar o mesmo conjunto de linhas a cada vez.
NewId()é insignificantemente mais lento que rand(checksum(*)), portanto, você pode não querer usá-lo em grandes conjuntos de registros.
Seleção com semente inicial:
declare@seed int
set@seed = Year(getdate())* month(getdate())/* any other initial seed here */selecttop10percent*from table_name
orderby rand(checksum(*)% seed)/* any other math function here */
Se você precisar selecionar o mesmo conjunto dado uma semente, isso parece funcionar.
No SQL Server, você pode combinar TABLESAMPLE com NEWID () para obter uma boa aleatoriedade e ainda assim ter velocidade. Isso é especialmente útil se você realmente deseja apenas 1 ou um número pequeno de linhas.
Com o SQL Server 2012+, você pode usar a consulta OFFSET FETCH para fazer isso em uma única linha aleatória
select*from MyTable ORDERBY id OFFSET n ROWFETCH NEXT 1ROWS ONLY
onde id é uma coluna de identidade e n é a linha que você deseja - calculada como um número aleatório entre 0 e count () - 1 da tabela (o deslocamento 0 é a primeira linha, afinal)
Isso funciona com buracos nos dados da tabela, desde que você tenha um índice para trabalhar com a cláusula ORDER BY. Também é muito bom para a aleatoriedade - enquanto você trabalha para passar, mas as imperfeições de outros métodos não estão presentes. Além disso, o desempenho é muito bom, em um conjunto de dados menor ele se mantém bem, embora eu não tenha tentado testes de desempenho sérios em vários milhões de linhas.
Dez anos atrás (2005) um cara disse que o uso ORDER BY RAND()é errado ...
Trejder
0
Eu tenho que concordar com o CD-MaN: Usar "ORDER BY RAND ()" funcionará bem em pequenas tabelas ou quando você fizer o SELECT apenas algumas vezes.
Também uso a técnica "num_value> = RAND () * ..." e, se realmente quero ter resultados aleatórios, tenho uma coluna "aleatória" especial na tabela que atualizo uma vez por dia. Essa única execução UPDATE levará algum tempo (especialmente porque você precisará ter um índice nessa coluna), mas é muito mais rápido do que criar números aleatórios para cada linha sempre que a seleção for executada.
Tenha cuidado porque o TableSample não retorna realmente uma amostra aleatória de linhas. Ele direciona sua consulta para examinar uma amostra aleatória das páginas de 8 KB que compõem sua linha. Em seguida, sua consulta é executada com base nos dados contidos nessas páginas. Devido à forma como os dados podem ser agrupados nessas páginas (pedido de inserção etc.), isso pode levar a dados que não são realmente uma amostra aleatória.
Parece que muitas das idéias listadas ainda usam pedidos
No entanto, se você usar uma tabela temporária, poderá atribuir um índice aleatório (como muitas das soluções sugeriram) e pegar o primeiro que seja maior que um número arbitrário entre 0 e 1.
Por exemplo (para DB2):
WITH TEMP AS(SELECT COMLUMN, RAND()AS IDX FROMTABLE)SELECTCOLUMNFROMTABLEWHERE IDX >.5FETCH FIRST 1ROW ONLY
Depois de considerar esta solução, encontrei uma falha fundamental em minha lógica. Isso retornaria consistentemente os mesmos pequenos valores de configuração, perto do início da tabela, porque presumo que, se houver uma distribuição uniforme entre 0 e 1, há 50% de chance de a primeira linha atender a esse critério.
Existe uma solução melhor para o Oracle em vez de usar dbms_random.value, enquanto requer varredura completa para ordenar linhas por dbms_random.value e é bastante lento para tabelas grandes.
Para o SQL Server 2005 e superior, estenda a resposta do @ GreyPanther para os casos em num_valueque não houver valores contínuos. Isso funciona também para casos em que não distribuímos conjuntos de dados uniformemente e quando num_valuenão é um número, mas um identificador exclusivo.
WITH CTE_Table (SelRow, num_value)AS(SELECT ROW_NUMBER()OVER(ORDERBY ID)AS SelRow, num_value FROMtable)SELECT*FROMtableWhere num_value =(SELECTTOP1 num_value FROM CTE_Table WHERE SelRow >= RAND()*(SELECT MAX(SelRow)FROM CTE_Table))
Respostas:
Veja esta postagem: SQL para selecionar uma linha aleatória de uma tabela de banco de dados . Ele passa por métodos para fazer isso no MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 e Oracle (o seguinte é copiado desse link):
Selecione uma linha aleatória com o MySQL:
Selecione uma linha aleatória com o PostgreSQL:
Selecione uma linha aleatória com o Microsoft SQL Server:
Selecione uma linha aleatória com o IBM DB2
Selecione um registro aleatório com o Oracle:
fonte
order by rand()
ou equivalentes em todos os dbs: |. também mencionado aqui .ORDER BY RAND()
é errado ...O(n)
comn
sendo o número de registros na tabela. Imagine que você tem 1 milhão de registros. Deseja realmente gerar 1 milhão de números aleatórios ou IDs exclusivos? Prefiro usarCOUNT()
e envolver isso em uma novaLIMIT
expressão com um único número aleatório.Soluções como Jeremies:
funcionam, mas precisam de uma varredura seqüencial de toda a tabela (porque o valor aleatório associado a cada linha precisa ser calculado - para que seja possível determinar o menor), o que pode ser bastante lento para tabelas de tamanho médio. Minha recomendação seria usar algum tipo de coluna numérica indexada (muitas tabelas têm essas como chaves primárias) e depois escrever algo como:
Isso funciona em tempo logarítmico, independentemente do tamanho da tabela, se
num_value
estiver indexado. Uma ressalva: isso assume quenum_value
é igualmente distribuído no intervalo0..MAX(num_value)
. Se o seu conjunto de dados se desviar fortemente dessa suposição, você obterá resultados distorcidos (algumas linhas aparecerão com mais frequência do que outras).fonte
Não sei o quão eficiente isso é, mas já o usei antes:
Como os GUIDs são bastante aleatórios, a ordem significa que você obtém uma linha aleatória.
fonte
ORDER BY RAND() LIMIT 1
TOP 1
enewid()
.leva
7.4 milliseconds
leva
0.0065 milliseconds
!Definitivamente vou com o último método.
fonte
rand()
retorna um número de ponto flutuante emn
que0 < n < 1
. Supondo quenum_value
seja um número inteiro, o valor de retorno derand() * max(num_value)
também será coagido a um número inteiro, truncando qualquer coisa após o ponto decimal. Por isso,rand() * max(num_value)
vai sempre ser inferiormax(num_value)
, razão pela qual a última linha nunca será selecionado.Você não disse qual servidor está usando. Nas versões mais antigas do SQL Server, você pode usar isso:
No SQL Server 2005 e superior, você pode usar
TABLESAMPLE
para obter uma amostra aleatória que pode ser repetida:fonte
Para SQL Server
newid () / order by funcionará, mas será muito caro para grandes conjuntos de resultados porque ele precisa gerar um ID para cada linha e, em seguida, classificá-los.
TABLESAMPLE () é bom do ponto de vista de desempenho, mas você obterá agrupamentos de resultados (todas as linhas em uma página serão retornadas).
Para uma amostra aleatória verdadeira com melhor desempenho, a melhor maneira é filtrar as linhas aleatoriamente. Encontrei o seguinte exemplo de código no artigo Manuais Online do SQL Server Limitando os conjuntos de resultados usando o TABLESAMPLE :
Quando executado em uma tabela com 1.000.000 de linhas, eis meus resultados:
Se você conseguir usar o TABLESAMPLE, ele fornecerá o melhor desempenho. Caso contrário, use o método newid () / filter. newid () / order by deve ser o último recurso se você tiver um grande conjunto de resultados.
fonte
Se possível, use instruções armazenadas para evitar a ineficiência de ambos os índices no RND () e criar um campo de número de registro.
fonte
A melhor maneira é colocar um valor aleatório em uma nova coluna apenas para esse fim e usar algo como isto (código pseudo + SQL):
Esta é a solução empregada pelo código MediaWiki. Obviamente, existe algum viés em relação a valores menores, mas eles descobriram que era suficiente agrupar o valor aleatório em torno de zero quando nenhuma linha é buscada.
A solução newid () pode exigir uma varredura completa da tabela para que cada linha possa receber um novo guia, que terá muito menos desempenho.
A solução rand () pode não funcionar de todo (ou seja, com MSSQL) porque a função será avaliada apenas uma vez e a cada linha será atribuído o mesmo número "aleatório".
fonte
Para o SQL Server 2005 e 2008, se quisermos uma amostra aleatória de linhas individuais (dos Manuais Online ):
fonte
No caso de usar RAND (), como não é recomendado , você pode simplesmente obter o ID máximo (= Max):
obter um aleatório entre 1..Max (= My_Generated_Random)
e, em seguida, execute este SQL:
Observe que ele verificará todas as linhas com IDs iguais ou superiores ao valor escolhido. Também é possível procurar a linha abaixo da tabela e obter um ID igual ou menor que o My_Generated_Random, e modificar a consulta da seguinte maneira:
fonte
Como apontado no comentário de @ BillKarwin na resposta de @ cnu ...
Ao combinar com um LIMIT, descobri que ele tem um desempenho muito melhor (pelo menos com o PostgreSQL 9.1) para JOIN com uma ordem aleatória em vez de ordenar diretamente as linhas reais: por exemplo
Apenas certifique-se de que o 'r' gere um valor de 'rand' para todos os possíveis valores de chave na consulta complexa associada a ele, mas ainda assim limite o número de linhas de 'r' sempre que possível.
O CAST como número inteiro é especialmente útil para o PostgreSQL 9.2, que possui otimização de classificação específica para tipos flutuantes de precisão inteira e única.
fonte
A maioria das soluções aqui visa evitar a classificação, mas elas ainda precisam fazer uma varredura seqüencial sobre uma tabela.
Também há uma maneira de evitar a varredura seqüencial alternando para a varredura de índice. Se você conhece o valor do índice da sua linha aleatória, pode obter o resultado quase instantaneamente. O problema é - como adivinhar um valor de índice.
A seguinte solução funciona no PostgreSQL 8.4:
Acima da solução, você adivinha 10 valores de índice aleatórios diferentes do intervalo 0 .. [último valor do id].
O número 10 é arbitrário - você pode usar 100 ou 1000, pois (surpreendentemente) não tem um grande impacto no tempo de resposta.
Há também um problema - se você tiver identificações esparsas, poderá perder . A solução é ter um plano de backup :) Nesse caso, uma ordem antiga pura por consulta random (). Quando o ID combinado se parece com isso:
Não é a cláusula ALL da união . Nesse caso, se a primeira parte retornar algum dado, a segunda NUNCA será executada!
fonte
No final, mas cheguei aqui pelo Google, então, por motivos de posteridade, adicionarei uma solução alternativa.
Outra abordagem é usar TOP duas vezes, com pedidos alternados. Não sei se é "SQL puro", porque usa uma variável no TOP, mas funciona no SQL Server 2008. Aqui está um exemplo que utilizo em uma tabela de palavras do dicionário, se quiser uma palavra aleatória.
Obviamente, @idx é um número inteiro gerado aleatoriamente que varia de 1 a COUNT (*) na tabela de destino, inclusive. Se sua coluna estiver indexada, você também será beneficiado. Outra vantagem é que você pode usá-lo em uma função, pois NEWID () não é permitido.
Por fim, a consulta acima é executada em cerca de 1/10 do tempo de execução de uma consulta do tipo NEWID () na mesma tabela. YYMV.
fonte
Você também pode tentar usar a
new id()
funçãoBasta escrever uma consulta e usar ordem por
new id()
função. É bastante aleatório.fonte
Para o MySQL obter registro aleatório
Mais detalhes http://jan.kneschke.de/projects/mysql/order-by-rand/
fonte
Ainda não vi essa variação nas respostas. Eu tinha uma restrição adicional onde precisava, com base em uma semente inicial, para selecionar o mesmo conjunto de linhas a cada vez.
Para MS SQL:
Exemplo mínimo:
Tempo de execução normalizado: 1,00
Exemplo NewId ():
Tempo de execução normalizado: 1,02
NewId()
é insignificantemente mais lento querand(checksum(*))
, portanto, você pode não querer usá-lo em grandes conjuntos de registros.Seleção com semente inicial:
Se você precisar selecionar o mesmo conjunto dado uma semente, isso parece funcionar.
fonte
No MSSQL (testado em 11.0.5569) usando
é significativamente mais rápido que
fonte
No SQL Server, você pode combinar TABLESAMPLE com NEWID () para obter uma boa aleatoriedade e ainda assim ter velocidade. Isso é especialmente útil se você realmente deseja apenas 1 ou um número pequeno de linhas.
fonte
Com o SQL Server 2012+, você pode usar a consulta OFFSET FETCH para fazer isso em uma única linha aleatória
onde id é uma coluna de identidade e n é a linha que você deseja - calculada como um número aleatório entre 0 e count () - 1 da tabela (o deslocamento 0 é a primeira linha, afinal)
Isso funciona com buracos nos dados da tabela, desde que você tenha um índice para trabalhar com a cláusula ORDER BY. Também é muito bom para a aleatoriedade - enquanto você trabalha para passar, mas as imperfeições de outros métodos não estão presentes. Além disso, o desempenho é muito bom, em um conjunto de dados menor ele se mantém bem, embora eu não tenha tentado testes de desempenho sérios em vários milhões de linhas.
fonte
fonte
ORDER BY RAND()
é errado ...Eu tenho que concordar com o CD-MaN: Usar "ORDER BY RAND ()" funcionará bem em pequenas tabelas ou quando você fizer o SELECT apenas algumas vezes.
Também uso a técnica "num_value> = RAND () * ..." e, se realmente quero ter resultados aleatórios, tenho uma coluna "aleatória" especial na tabela que atualizo uma vez por dia. Essa única execução UPDATE levará algum tempo (especialmente porque você precisará ter um índice nessa coluna), mas é muito mais rápido do que criar números aleatórios para cada linha sempre que a seleção for executada.
fonte
Tenha cuidado porque o TableSample não retorna realmente uma amostra aleatória de linhas. Ele direciona sua consulta para examinar uma amostra aleatória das páginas de 8 KB que compõem sua linha. Em seguida, sua consulta é executada com base nos dados contidos nessas páginas. Devido à forma como os dados podem ser agrupados nessas páginas (pedido de inserção etc.), isso pode levar a dados que não são realmente uma amostra aleatória.
Consulte: http://www.mssqltips.com/tip.asp?tip=1308
Esta página do MSDN para TableSample inclui um exemplo de como gerar uma amostra de dados realmente aleatória.
http://msdn.microsoft.com/en-us/library/ms189108.aspx
fonte
Parece que muitas das idéias listadas ainda usam pedidos
No entanto, se você usar uma tabela temporária, poderá atribuir um índice aleatório (como muitas das soluções sugeriram) e pegar o primeiro que seja maior que um número arbitrário entre 0 e 1.
Por exemplo (para DB2):
fonte
Uma maneira simples e eficiente de http://akinas.com/pages/en/blog/mysql_random_row/
fonte
Existe uma solução melhor para o Oracle em vez de usar dbms_random.value, enquanto requer varredura completa para ordenar linhas por dbms_random.value e é bastante lento para tabelas grandes.
Use isto:
fonte
Para Firebird:
fonte
Para o SQL Server 2005 e superior, estenda a resposta do @ GreyPanther para os casos em
num_value
que não houver valores contínuos. Isso funciona também para casos em que não distribuímos conjuntos de dados uniformemente e quandonum_value
não é um número, mas um identificador exclusivo.fonte
A função aleatória do sql pode ajudar. Além disso, se você deseja limitar a apenas uma linha, basta adicioná-la no final.
fonte