Estou otimizando muitas consultas existentes em meu projeto. A solução da Quassnoi me ajudou a agilizar muito as consultas! No entanto, acho difícil incorporar a referida solução em todas as consultas, especialmente para consultas complicadas envolvendo muitas subconsultas em várias tabelas grandes.
Portanto, estou usando uma solução menos otimizada. Basicamente, ele funciona da mesma maneira que a solução de Quassnoi.
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / [accomodation_table_row_count]
LIMIT $size
$size * $factor / [accomodation_table_row_count]
calcula a probabilidade de escolher uma linha aleatória. O rand () irá gerar um número aleatório. A linha será selecionada se rand () for menor ou igual à probabilidade. Isso efetivamente executa uma seleção aleatória para limitar o tamanho da tabela. Como há uma chance de que ele retorne menos do que o limite de contagem definido, precisamos aumentar a probabilidade para garantir que estamos selecionando linhas suficientes. Portanto, multiplicamos $ size por um $ fator (geralmente defino $ fator = 2, funciona na maioria dos casos). Finalmente fazemos olimit $size
O problema agora é calcular o accomodation_table_row_count . Se soubermos o tamanho da tabela, PODEMOS codificar o tamanho da tabela. Isso seria executado mais rápido, mas obviamente não é o ideal. Se você estiver usando o Myisam, obter a contagem da mesa é muito eficiente. Como estou usando o innodb, estou apenas fazendo uma simples contagem + seleção. No seu caso, seria assim:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / (select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
A parte complicada é calcular a probabilidade certa. Como você pode ver, o código a seguir, na verdade, apenas calcula o tamanho aproximado da tabela temporária (na verdade, muito aproximado!): (select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
Mas você pode refinar essa lógica para fornecer uma aproximação mais próxima do tamanho da tabela. Observe que é melhor selecionar OVER do que sub-selecionar as linhas. ou seja, se a probabilidade for definida como muito baixa, você corre o risco de não selecionar linhas suficientes.
Esta solução é executada mais lentamente do que a solução de Quassnoi, pois precisamos recalcular o tamanho da tabela. No entanto, acho essa codificação muito mais gerenciável. Esta é uma troca entre precisão + desempenho e complexidade de codificação . Dito isso, em tabelas grandes isso ainda é muito mais rápido do que Order by Rand ().
Nota: Se a lógica da consulta permitir, execute a seleção aleatória o mais cedo possível antes de qualquer operação de junção.