verifica padrões que não existem no sqlite

4

Expliquei uma situação semelhante com arquivos de texto simples em Grande número de padrões de arquivo enorme . Muitas pessoas disseram que eu deveria, então agora estou migrando meus dados para um banco de dados sqlite:

Eu tenho um arquivo do qual eu extraio cerca de 10.000 padrões. Então eu verifico se o banco de dados não contém tais padrões. Se isso não acontecer, preciso salvá-los externamente em file para processamento adicional:

for id in $(grep ^[0-9] keys); do
  if [[ -z $(sqlite3 db.sqlite "select id from main where id = $id") ]]; then
    echo $id >>file
  fi
done

Como sou novo no SQL, não consegui encontrar uma maneira simples de fazer isso. Além disso, esse loop é inútil, pois é 20 vezes mais lento do que o obtido com awk na URL mencionada.

Como o banco de dados é enorme, continua crescendo e eu executo esse loop com muita frequência, é possível fazer isso mais rápido?

    
por Teresa e Junior 31.01.2012 / 01:54

2 respostas

1

Para cada padrão, você está invocando uma nova instância do programa sqlite , que se conecta ao banco de dados novamente. Isso é um desperdício. Você deve criar uma única consulta que procure por qualquer uma das chaves e, em seguida, executar essa consulta. Os clientes de banco de dados são bons em executar consultas grandes.

Se as linhas correspondentes no arquivo keys contiverem apenas dígitos, você poderá criar a consulta da seguinte forma:

{
  echo 'select id from main where id in (';
  <keys grep -x '[0-9][0-9]*' |     # retain only lines containing only digits
  sed -e '1! s/^/, /' |             # add ", " at the beginning of every line except the first
  echo ');'
} | sqlite3 db.sqlite

Para obter dados de entrada mais gerais, você tem a ideia: usar transformações de texto para criar uma única consulta grande. Tenha cuidado para validar sua entrada ; aqui nos certificamos de que o que é injetado na consulta é sintaticamente válido. Na verdade, há um caso de canto no exemplo acima: se não houver correspondência no arquivo, a sintaxe SQL será inválida; Se isso acontecer, você precisará tratar este caso especialmente. Aqui está um código mais complexo que cuida do caso vazio:

<keys grep -x '[0-9][0-9]*' |
if read first; then {
    echo 'select id from main where id in (' "$first"
    sed -e 's/^/, /'
    echo ');'
  } | sqlite3 db.sqlite
fi
    
por 01.02.2012 / 01:39
1

Primeiramente, você realmente substitui o if por uma lista. Na verdade, eu até substitui o [[]] s por [] s e, em seguida, execudo em dash ou outro isqueiro sh . Isso até parece simples o suficiente para largar todo o for , e correr com xargs (sempre minha preferência, melhor desempenho) Então, por exemplo, talvez algo assim ...

grep ^[0-9] keys | xargs -P0 -I '{id}' \
sh -c '[ -z "$(sqlite3 db.sqlite =\"select id from main where id = '{id}'\")" ] && \
echo '{id}' >> file'

Meu escape provavelmente está desativado, mas isso deve apontar você na direção certa. Eu suspeitaria que isso ocorreria MUITO mais rápido, pelo menos porque você estaria executando em paralelo via -P .

Se por algum motivo, mesmo isso está rastreando, você sempre pode olhar para algo que despeja o banco de dados sqlite. Você provavelmente estaria escrevendo um roteiro, se você adotasse essa abordagem. Eu só consideraria isso, se fosse necessário.

    
por 31.01.2012 / 07:18