consultas em linha são uma má idéia?

votos
3

Eu tenho uma tabela contendo os tempos de execução para geradores em locais diferentes, e eu quero para selecionar a entrada mais recente para cada site. Cada gerador é executado uma vez ou duas vezes por semana.

Eu tenho uma consulta que vai fazer isso, mas eu me pergunto se é a melhor opção. Não posso deixar de pensar que utilizando WHERE x IN (SELECT ...) é preguiçoso e não a melhor maneira de formular a consulta - qualquer consulta.

A tabela é a seguinte:

CREATE TABLE generator_logs (
    id integer NOT NULL,
    site_id character varying(4) NOT NULL,
    start timestamp without time zone NOT NULL,
    end timestamp without time zone NOT NULL,
    duration integer NOT NULL
);

E a consulta:

SELECT id, site_id, start, end, duration 
FROM generator_logs
WHERE start IN (SELECT MAX(start) AS start 
                FROM generator_logs 
                GROUP BY site_id) 
ORDER BY start DESC

Não há uma enorme quantidade de dados, por isso não estou preocupado sobre como otimizar a consulta. No entanto, eu tenho que fazer coisas semelhantes em tabelas com 10s de milhões de linhas, (mesas grandes, tanto quanto eu estou preocupado!) E há otimização é mais importante.

Então, há uma melhor consulta para isso, e são consultas em linha geralmente uma má idéia?

Publicado 21/11/2008 em 12:16
fonte usuário
Em outras línguas...                            


5 respostas

votos
0

No MySQL poderia ser problemático porque última vez que verifiquei que era incapaz de otimizar subqueries efetivamente (Ie: por consulta de reescrita)

Muitos DBMS têm planejadores da consulta genética que irá fazer a mesma coisa, independentemente da sua estrutura de consultas de entrada.

MySQL irá, em alguns casos para essa situação cria uma tabela temporária, outras vezes não, e dependendo das circunstâncias, indexação, condtions, subconsultas pode ainda ser bastante rápido.

Alguns reclamam que subqueries são difíceis de ler, mas eles são perfeitamente bem se você garfo-los em variáveis ​​locais.

$maxids = 'SELECT MAX(start) AS start FROM generator_logs GROUP BY site_id';
$q ="     
    SELECT id, site_id, start, \"end\", duration 
       FROM generator_logs
       WHERE start IN ($maxids) 
       ORDER BY start DESC
";
Respondeu 21/11/2008 em 12:22
fonte usuário

votos
4

Se a sua consulta não ser correlacionados? ou seja:

SELECT id, site_id, start, "end", duration 
FROM generator_logs g1
WHERE start = (SELECT MAX(g2.start) AS start 
               FROM generator_logs  g2
               WHERE g2.site_id = g1.site_id) 
ORDER BY start DESC

Caso contrário, você vai potencialmente pegar mais recentes não-registros cujo valor inicial acontece para coincidir com o mais recente começo para um site diferente.

Ou alternativamente:

SELECT id, site_id, start, "end", duration 
FROM generator_logs g1
WHERE (site_id, start) IN (SELECT site_id, MAX(g2.start) AS start 
                           FROM generator_logs  g2
                           GROUP BY site_id)
ORDER BY start DESC
Respondeu 21/11/2008 em 12:37
fonte usuário

votos
1

Eu usaria se junta como eles executam muito melhor, então cláusula "IN":

select gl.id, gl.site_id, gl.start, gl."end", gl.duration 
from 
    generator_logs gl
    inner join (
        select max(start) as start, site_id
        from generator_logs 
        group by site_id
    ) gl2
        on gl.site_id = gl2.site_id
        and gl.start = gl2.start

Também como Tony apontou que estava faltando correlação em sua consulta original

Respondeu 21/11/2008 em 13:44
fonte usuário

votos
0

Este problema - encontrar não apenas a do MAX, mas o resto da linha correspondente - é comum. Felizmente, Postgres fornece uma boa maneira de fazer isso com uma consulta, usando DISTINCT ON:

SELECT DISTINCT ON (site_id)
  id, site_id, start, "end", duration
FROM generator_logs
ORDER BY site_id, start DESC;

DISTINCT ON (site_id)significa "retornar um registro por site_id". O fim da cláusula determina que registro que é. Note, no entanto, que isto é sutilmente diferente da sua consulta original - se você tiver dois registros para o mesmo local com o mesmo start, a sua consulta retornaria dois registros, enquanto isso retorna apenas um.

Respondeu 14/06/2014 em 12:14
fonte usuário

votos
0

Uma maneira de encontrar registros com o valor MAX por grupo é selecionar os registros para o qual não há nenhum registro dentro do mesmo grupo com um valor superior:

SELECT id, site_id, "start", "end", duration 
FROM generator_logs g1
WHERE NOT EXISTS (
    SELECT 1
    FROM generator_logs g2
    WHERE g2.site_id = g1.site_id
    AND g2."start" > g1."start"
    );
Respondeu 14/06/2014 em 12:33
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more