É possível evitar o filesort?

10

É possível evitar 'Using temporary' e 'Using filesort' para a seguinte consulta SELECT? Não consigo descobrir uma maneira de fazer isso.

Eu tentei adicionar índices, tanto para top_expire quanto para programa, mas não ajudou. Com o ORDER BY a consulta leva mais de 1 segundo e sem ele são apenas 0,003 segundos no localhost

Inquerir

SELECT ad.*, p.link
    FROM (SELECT ad.*
        FROM mod_ad ad 
        JOIN mod_ad_auta auta ON ad.id = auta.ad_id
        WHERE ad.active != 0 AND ad.usr_active != 0 AND ad.expire > 1371151608  AND ad.cat_id = '1' AND ad.price <= '10000' 
          AND auta.rocnik BETWEEN '1950' AND '2013' 
          AND auta.km BETWEEN '0' AND '500000'
        ORDER BY top_expire DESC, program DESC,  ad.id DESC  LIMIT 0,10) as ad
JOIN pages p ON ad.page_id=p.page_id;

Esquema

CREATE TABLE `mod_ad` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `page_id` int(10) unsigned NOT NULL,
  `cat_id` int(10) unsigned NOT NULL,
  `subcat_id` int(10) unsigned NOT NULL,
  `program` tinyint(1) unsigned NOT NULL,
  `region_id` int(10) unsigned NOT NULL,
  `zone_id` int(10) unsigned NOT NULL,
  `city_id` int(10) unsigned NOT NULL,
  `sort` enum('firm','priv') NOT NULL,
  `type` enum('predaj','kúpa','výmena','darujem','hľadám','ponúkam','iné') NOT NULL,
  `condition` varchar(24) NOT NULL,
  `name` varchar(128) NOT NULL,
  `desc` text NOT NULL,
  `location` varchar(128) NOT NULL,
  `keywords` varchar(255) NOT NULL,
  `price` decimal(10,2) NOT NULL,
  `price_type` varchar(20) NOT NULL,
  `cperson` varchar(128) NOT NULL,
  `firmname` varchar(128) NOT NULL,
  `zip` varchar(5) NOT NULL,
  `email` varchar(255) NOT NULL,
  `tel` varchar(20) NOT NULL,
  `tel2` varchar(20) NOT NULL,
  `web` varchar(255) NOT NULL,
  `video` varchar(255) NOT NULL,
  `marked_expire` int(11) unsigned NOT NULL,
  `top_expire` int(11) unsigned NOT NULL,
  `ad_hot_expire` int(11) unsigned NOT NULL,
  `ad_border_expire` int(11) unsigned NOT NULL,
  `ad_heading_expire` int(11) unsigned NOT NULL,
  `ad_weblink_expire` int(11) unsigned NOT NULL,
  `active` int(10) unsigned NOT NULL,
  `usr_active` int(10) unsigned NOT NULL,
  `added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `archive` int(10) unsigned NOT NULL,
  `expire` int(11) unsigned NOT NULL,
  `token` varchar(32) NOT NULL,
  `views` mediumint(9) NOT NULL,
  `ip` varchar(15) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `page_id` (`page_id`),
  KEY `cat_id` (`cat_id`),
  KEY `region_id` (`region_id`),
  KEY `zone_id` (`zone_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `mod_ad_auta` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `ad_id` int(10) unsigned NOT NULL,
  `model` int(10) unsigned NOT NULL,
  `rocnik` smallint(5) unsigned NOT NULL,
  `palivo` varchar(10) NOT NULL,
  `karoseria` varchar(12) NOT NULL,
  `km` mediumint(8) unsigned NOT NULL,
  `prevodovka` varchar(12) NOT NULL,
  `farba` varchar(16) NOT NULL,
  `metaliza` tinyint(1) unsigned NOT NULL,
  `obsah` smallint(5) unsigned NOT NULL,
  `vykon` smallint(5) unsigned NOT NULL,
  `vybava` text NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ad_id` (`ad_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
michalzuber
fonte
Qual versão do MySQL?
Mike Sherrill 'Cat Recall'
Em localhost 5.6.11, mas em hospedagem compartilhada vai ser mysql-5.1.63-Percona
michalzuber

Respostas:

13

Os documentos dizem

Em alguns casos, o MySQL não pode usar índices para resolver a ORDER BY, embora ainda use índices para encontrar as linhas que correspondem à cláusula WHERE. Esses casos incluem o seguinte:

e depois liste muitas circunstâncias que impedem o MySQL de usar índices. Entre eles estão

  • Você usa ORDER BY em teclas diferentes
  • A chave usada para buscar as linhas não é a mesma usada na chave ORDER BY

e provavelmente existem outros.

Para evitar um tipo de arquivo, você precisa encontrar uma maneira de obter o que deseja, sem precisar executar nenhuma dessas (muitas) condições documentadas.

Você também pode

  • Aumente o tamanho da variável sort_buffer_size.
  • Aumente o tamanho da variável read_rnd_buffer_size.
  • Use menos RAM por linha declarando as colunas apenas do tamanho necessário para manter os valores armazenados nelas.
  • Altere tmpdir para apontar para um sistema de arquivos dedicado com grandes quantidades de espaço livre.

(Mesmo link.)

Consulte também os documentos para Otimização de consultas LIMIT , que interagem com ORDER BY.

Mike Sherrill 'Recolha de Gatos'
fonte
11
Obrigado pela explicação. Eu adicionei o campo ORDER BY ao índice e agora ele não está usando o filesort.
Adrian P.