O lixo transitório é coletado?

61

Esta pergunta me fez pensar que os feeds RSS temporários em wp_options não foram removidos automaticamente?

Os transitórios devem expirar e serem excluídos. No entanto, a única maneira de ver isso é quando o transitório expirar e for solicitado, e ele será excluído durante a solicitação.

E se o transitório expirar, mas nunca for solicitado depois disso? Pela descrição no Codex, pensei que algum tipo de coleta de lixo estivesse implícita. Agora não tenho tanta certeza e não consigo encontrar nenhum código que execute isso.

Então, ele ficará preso no banco de dados para sempre?

Rarst
fonte
teoricamente eles devem ser removidos quando cron é executado (se estiverem expirado)
onetrickpony
11
@ Ameba Ambitious sim, eu meio que mencionei isso em questão. O que quero dizer é - a criação transitória não assume nem garante que será solicitada. Salientando a pergunta original - quando e se o transitório expirado for excluído, se eu nunca conseguir ?
Rarst
11
pressupõe que você limpe os dados expirados, mas sim, você está certo, há situações em que eles nunca seriam excluídos. Como remover um widget que usa transientes. Você deve enviar um bilhete no trac para este :)
onetrickpony
11
@Rarst - Parece uma coisa perfeita para escrever um patch e enviar para o trac?
MikeSchinkel
11
Ticket trac relacionado: core.trac.wordpress.org/ticket/20316
Stephen Harris

Respostas:

45

Eles agora são

A partir do WordPress 3.7, os transitórios expirados são excluídos nas atualizações do banco de dados, consulte # 20316


Resposta antiga

Se alguém não pode me mostrar o contrário, parece que os transitórios não são coletados como lixo, afinal. O que piora é que, diferentemente das opções, elas não são garantidas para serem armazenadas no banco de dados. Portanto, não há uma maneira confiável de buscar a lista de todos os transitórios para verificar sua validade.

Algum código improvisado para fazer coleta de lixo se o banco de dados for usado para armazenamento:

add_action( 'wp_scheduled_delete', 'delete_expired_db_transients' );

function delete_expired_db_transients() {

    global $wpdb, $_wp_using_ext_object_cache;

    if( $_wp_using_ext_object_cache )
        return;

    $time = isset ( $_SERVER['REQUEST_TIME'] ) ? (int)$_SERVER['REQUEST_TIME'] : time() ;
    $expired = $wpdb->get_col( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout%' AND option_value < {$time};" );

    foreach( $expired as $transient ) {

        $key = str_replace('_transient_timeout_', '', $transient);
        delete_transient($key);
    }
}
Rarst
fonte
$ time = $ _SERVER ['REQUEST_TIME']; e, em seguida, usando $ time na consulta SQL - não faça isso. Lide com mais cuidado com as variáveis ​​/ valores $ _SERVER para evitar injeções de SQL.
hakre
@hakre hm ... Eu escolhi isso na apresentação sobre o desempenho do PHP que o recomendou sobre o uso, o time()que pode causar bugs (a execução não é instantânea por natureza). O tempo de solicitação está sendo definido pelo próprio PHP, não vem de nenhum tipo de dado fornecido pelo usuário. Por que essa vulnerabilidade?
Rarst
@Rarst: Eu não disse que você não deveria usá-lo, você deve apenas garantir que ele seja codificado com segurança para ser usado dentro da consulta SQL. Você deve fazer isso com todas as variáveis ​​de uma fonte externa. As variáveis ​​$ _SERVER podem não estar definidas conforme o esperado e, pelo contrário, definidas pelo usuário solicitante. Eu só queria propagar algumas boas práticas de codificação. Como sempre, para aprender sobre o estado real da disponibilidade, consulte os documentos. Para o PHP 4 por exemplo, tal variável não existe e pode ser substituído por um cabeçalho personalizado ou variável de ambiente - php.net/manual/en/reserved.variables.server.php
hakre
@hakre fixo (eu acho), obrigado por PHP4 lembrete btw (Eu não posso esperar para WordPress para soltar o apoio dela)
Rarst
Isso parece muito melhor aos meus olhos;). Vamos torcer para que não haja nenhum problema com time () e números inteiros negativos que possam excluir todos ou nenhum transiente por acidente. Nunca confie em um sistema em execução: P
hakre
20

Movendo alguns dos comentários da discussão para uma resposta, com reformulação e reformatação.

Basicamente, o que se resume é que, a menos que você tenha um caso extremamente extremo, eles realmente não precisam ser "coletados de lixo". Se você nunca os buscar, não importa se eles estão lá ou não.

Veja, os transitórios são armazenados na tabela de opções por padrão. Em uma instalação básica, a tabela de opções terá talvez 100 entradas. Cada transitório adiciona mais duas entradas, mas mesmo se você tiver milhares, elas não afetam a velocidade do site, pois não são carregadas automaticamente.

Na inicialização, o WordPress carrega as opções na memória, mas apenas carrega opções com o sinalizador de carregamento automático ativado. Os transitórios não entendem isso e, portanto, não são carregados na memória. Somente os transitórios que são realmente usados ​​posteriormente terão um custo.

Da perspectiva do banco de dados, a tabela de opções possui índices na identificação da opção e no nome da opção. Os transitórios são sempre carregados com base no nome (chave) e, portanto, as pesquisas para eles são sempre simples, com um único valor de chave exclusivo. Portanto, a pesquisa é O (log (n)) e é super rápida. Com um Big-O de log (n), você teria que entrar nos milhões e milhões de linhas antes que isso se tornasse perceptível. Francamente, a sobrecarga na configuração e desmontagem da consulta, juntamente com a transferência de dados real, é muito mais longa. A consulta em si é executada essencialmente em tempo zero por comparação. Portanto, simplesmente ter linhas extras não utilizadas não afeta nada, mas usa espaço em disco extra.

A indexação em bancos de dados é um desses tipos de idéias que não fazem sentido para pessoas que realmente não entenderam o que está acontecendo nos bastidores. Os bancos de dados são projetados para recuperação rápida de dados desde o início e podem lidar com esse tipo de coisa sem problemas. Esta é uma ótima leitura: http://en.wikipedia.org/wiki/Index_(database )

Agora, a limpeza da maneira mais óbvia (chamando SQL DELETE neles) não os exclui do banco de dados. Apenas os remove do índice e marca a linha como "excluída". Novamente, é assim que os bancos de dados funcionam. Para realmente limpar o espaço em disco, você deve continuar e executar uma OPTIMIZE TABLE posteriormente, e essa não é uma operação rápida. Leva tempo. Provavelmente mais tempo do que vale a pena. Provavelmente não é suficiente para economizar no tempo da CPU, no total.

Se você tiver algum caso que esteja causando uma inserção contínua de novos transientes que não estão sendo usados, será necessário encontrar o problema subjacente. O que está inserindo esses transitórios? Eles estão usando uma chave de alteração ou mutação? Nesse caso, o plug-in ou código que causou isso deve ser corrigido para, basicamente, não fazer isso. Isso será mais útil, porque é provável que o código que não os esteja criando adequadamente também não os recupere e, portanto, faça mais trabalho do que precisa.

Por outro lado, pode haver um caso em que transitórios estão sendo criados para algo como todas as postagens. Isso pode ser perfeitamente aceitável. Eu mesmo faço isso no SFC, para armazenar os comentários recebidos do Facebook. Cada postagem tem um potencial transitório associado a ela, o que significa duas linhas extras por postagem. Se você tiver 10 mil postagens, terá 20 mil linhas na tabela de opções (eventualmente). Isso não é ruim ou lento, porque, novamente, há muito pouca diferença entre 100 e 20.000 linhas, na medida em que os bancos de dados realmente se importam. Está tudo indexado. É rápido como o diabo. Sub-sub-milissegundos.

Quando você começa a entrar em milhões de linhas, fico preocupada. Quando o tamanho da tabela de opções aumenta acima de centenas de megabytes, eu ficaria preocupado o suficiente para examinar melhor. Mas de um modo geral, isso não é um problema, exceto em casos extremos. Certamente não é um problema para nada menor do que algo como um grande site de notícias, com centenas de milhares de postagens. E para qualquer site grande o suficiente para que seja um problema, você deve usar algum tipo de cache de objeto externo e, nesse caso, os transitórios são armazenados automaticamente no local e não no banco de dados.

Otto
fonte
11
NB: transientes sem expiração não se autloaded, e sem vencimento é o padrão , então onde uma aplicação / plugin está criando lotes de transientes e não definir uma expiração eles estarão usando pedaços de memória em cada carregamento da página / post.
Webaware
Não há razão para usar um "transitório sem vencimento", porque isso é basicamente idêntico a uma "opção" normal.
Otto
11
Claro, mas é o padrão . Como tal, muitos autores de plug-ins estão adicionando transientes não expirados.
Webaware
11
Bem, a solução aqui é simples: não use esses plugins. Eles estão fazendo errado. Os transitórios não devem ser usados ​​como sessões, você não deve usá-los sem uma expiração significativa e eles não devem ter chaves de mutação ou alteração.
Otto
2
Diga, 7 dias. Se o autor de um plugin / tema quiser algo maior ou menor, ele o especificará. Se eles quiserem o carregamento automático, eles não deverão especificar 0 para expiração (= infinito), mas é o que eles têm atualmente com o parâmetro de expiração executando tarefas duplas como o parâmetro de carregamento automático yes / no. De qualquer forma, a expiração padrão também não deve levar ao carregamento automático = yes como padrão; isso é apenas pedir problemas.
Webaware
18

Otto - Eu não poderia discordar mais de você. A questão é que, eventualmente, com todos esses transitórios, o tamanho da tabela se torna ridículo. Não são necessários milhões de linhas para atolar. Atualmente, estou lidando com uma tabela de opções com mais de 130 mil linhas e trava regularmente. Como o campo de valor é um tipo de texto grande, mesmo procurando apenas as linhas "carregamento automático" se torna um pesadelo de desempenho. Esses campos de valor são armazenados separadamente do restante dos dados da linha. Mesmo que faça parte da mesma tabela, as junções devem ocorrer para exibir as linhas que você deseja. Associações que agora levam uma eternidade, porque os dados de que você precisa estão espalhados por todo o lugar no disco. A criação de perfil (usando o Jet Profiler para mysql) provou isso.

Adicionar carregamento automático à chave em cluster pode ajudar a resolver esse problema. O armazenamento em cluster no Desc de carregamento automático, ID ASC, por exemplo, permitiria que todas as linhas de carregamento automático se agrupassem primeiro no disco. Mesmo assim, acho que você está vendo uma enorme tensão do ponto de vista do banco de dados.

Pessoalmente, acho que o design deste sistema é maluco. A tabela de opções parece ter se transformado em algo genérico para muitas coisas. Tudo bem se o campo de valor for pequeno o suficiente para ser incluído na mesma página que o restante dos dados da linha e puder ser indexado de maneira eficaz. Infelizmente não é esse o caso. Quem criou isso precisa voltar para a classe DB101.

myke
fonte
5
verdadeiro, mas consideram que quando o desenvolvimento WordPress começou, ninguém pensou que iria chegar a ter milhares de plugins usando a tabela opções como seu armazenamento de dados :)
onetrickpony
@onetrickpony é por isso que é importante sempre tomar seu tempo e fazer as coisas direito, se você espera que ele seja grande dia ou não :)
Mahmoud Al-Qudsi