¿Grabar un archivo enorme (80 GB) de alguna manera para acelerarlo?

113
 grep -i -A 5 -B 5 'db_pd.Clients'  eightygigsfile.sql

Esto se ha estado ejecutando durante una hora en un servidor Linux bastante potente que de otra manera no está sobrecargado. ¿Alguna alternativa a grep? Cualquier cosa sobre mi sintaxis que pueda mejorarse (¿egrep, fgrep mejor?)

El archivo está realmente en un directorio que se comparte con un montaje en otro servidor, pero el espacio en disco real es local, por lo que no debería hacer ninguna diferencia.

el grep está tomando hasta el 93% de la CPU

zzapper
fuente
8
Dependiendo de su localidad, el -iconmutador puede ralentizar el proceso, intente sin -io con LC_ALL=C grep .... Además, si solo está buscando una cadena fija, use grep -F.
Thor
5
Como mencionó @dogbane, el uso de la variable LC_ALL = C junto con fgrep puede acelerar su búsqueda. Hice algunas pruebas y pude lograr un aumento de rendimiento del 1400% y escribí un artículo detallado por qué esto está en mi publicación de
aceleración de
Tengo curiosidad, ¿qué archivo tiene un tamaño de 80 GB? Me gustaría pensar que cuando un archivo se vuelve tan grande, puede haber una mejor estrategia de almacenamiento (por ejemplo, rotación de archivos de registro o categorización jerárquica en diferentes archivos y carpetas). Además, si los cambios solo ocurren en ciertos lugares del archivo (por ejemplo, al final), entonces simplemente almacene algunos resultados grep de la sección anterior que no cambian y en lugar de grep del archivo original, grep el archivo de resultados almacenado.
Sridhar Sarnobat
Me decidí por github.com/google/codesearch : tanto la indexación como la búsqueda son ultrarrápidas (escritas en Go). cindex .para indexar su carpeta actual, entonces csearch db_pd.Clients.
ccpizza
1
Si su archivo estuviera indexado u ordenado, esto podría hacerse mucho más rápido. La búsqueda de cada línea es O (n) por definición, mientras que un archivo ordenado se puede buscar dividiéndolo en dos; en ese momento, estaría hablando menos de un segundo para buscar su 80gb (de ahí por qué una base de datos indexada de 80gb no toma tiempo en absoluto para un SELECT simple, mientras que su grep toma ... bueno, tanto tiempo como sea necesario).
Charles Duffy

Respuestas:

148

Aquí hay algunas opciones:

1) Prefije su comando grep con LC_ALL=Cpara usar la configuración regional C en lugar de UTF-8.

2) Úselo fgrepporque está buscando una cadena fija, no una expresión regular.

3) Elimine la -iopción, si no la necesita.

Entonces tu comando se convierte en:

LC_ALL=C fgrep -A 5 -B 5 'db_pd.Clients' eightygigsfile.sql

También será más rápido si copia su archivo al disco RAM.

dogbane
fuente
5
eso fue MUCHO más rápido en un orden de magnitud gracias. Por cierto, agregué -n para obtener los números de línea. También tal vez un -m para salir después del partido
zzapper
5
¡Vaya, muchas gracias @dogbane, gran consejo! Esto me llevó por un túnel de investigación para descubrir por qué LC_ALL = C acelera grep y fue una experiencia muy esclarecedora.
JacobN
7
A algunas personas (no a mí) les gusta grep -Fmás quefgrep
Walter Tross
2
Tengo entendido que LANG=C(en lugar de LC_ALL=C) es suficiente y es más fácil de escribir.
Walter Tross
2
@Adrian fgrepes otra forma de escribir grep -F, como man fgrepte diré. Algunas versiones mantambién dicen que la primera está en desuso para la segunda, pero la forma más corta es demasiado conveniente para morir.
Walter Tross
36

Si tiene una CPU multinúcleo, realmente recomendaría GNU en paralelo . Para grep de un archivo grande en uso paralelo:

< eightygigsfile.sql parallel --pipe grep -i -C 5 'db_pd.Clients'

Dependiendo de sus discos y CPU, puede ser más rápido leer bloques más grandes:

< eightygigsfile.sql parallel --pipe --block 10M grep -i -C 5 'db_pd.Clients'

No está del todo claro a partir de su pregunta, pero otras opciones grepincluyen:

  • Dejando caer la -ibandera.
  • Usando la -Fbandera para una cuerda fija
  • Deshabilitar NLS con LANG=C
  • Establecer un número máximo de coincidencias con la -mbandera.
Steve
fuente
2
Si es un archivo real, utilice en --pipepartlugar de --pipe. Es mucho mas rapido.
Ole Tange
Este patrón de uso no compatible incluye espacio, necesitamos usarlo así: paralelo - tubería - bloque 10M "/ usr / bin / grep -F -C5 -e 'Cuidado de animales y mascotas'"
zw963
¿Qué significa el <carácter que precede al comando paralelo?
elcortegano
1
@elcortegano: Eso es lo que se llama E / S redirección . Básicamente, lee la entrada del siguiente nombre de archivo. Similar a, cat file.sql | parallel ...pero evita un UUOC . GNU paralelo también tiene una forma de leer la entrada de un archivo usando parallel ... :::: file.sql. HTH.
Steve
10

Alguna mejora trivial:

  • Elimine la opción -i, si puede, no distingue entre mayúsculas y minúsculas es bastante lento.

  • Reemplazar .por\.

    Un solo punto es el símbolo de expresión regular para que coincida con cualquier carácter, que también es lento

BeniBela
fuente
3

Dos líneas de ataque:

  • ¿Está seguro, necesita -io tiene la posibilidad de deshacerse de él?
  • ¿Tienes más núcleos para jugar? grepes de un solo subproceso, por lo que es posible que desee iniciar más de ellos en diferentes desplazamientos.
Eugen Rieck
fuente
1
< eightygigsfile.sql parallel -k -j120% -n10 -m grep -F -i -C 5 'db_pd.Clients'  

Si necesita buscar varias cadenas, grep -f strings.txt ahorra mucho tiempo. Lo anterior es una traducción de algo que estoy probando actualmente. el valor de la opción -j y -n parecía funcionar mejor para mi caso de uso. El grep -F también marcó una gran diferencia.

usuario584583
fuente