martes, 29 de abril de 2008

Mi solución al problema de inserción masiva en SQL Server

El título de este artículo puede parecer un poco egocéntrico pero hay que tener en cuenta que es la continuación de este otro y que además me refiero a una solución valida al problema que planteé en el entorno de producción que me afecta.

Recapitulando un poco para el que no quiera leerse el post enlazado, el problema en cuestión era conseguir unos 50 000 inserciones en un SGBD MS SQLServer. Todo ello sin ejecutar cada vez un

INSERT INTO MiTabla ...

El caso es que dicho entorno de producción tiene una particularidad tal vez no muy deseable: el SGBD y el servidor web corren en la misma máquina. Debido a esto se pasaba por mi cabeza que tal vez un Bulk Insert fuese una buena solución pero no me lo terminaba de creer porque suponía que esa instrucción se convertiría posteriormente en mis 50 000 "insert into", con lo cual incluso perdería mas tiempo.

El código fuente que utilicé aproximadamente en mis pruebas es el siguiente:


define("MAX",100000);
define("TAM_BLOQUE",10000);
mssql_connect("miservidor","miusuario","mipass");
mssql_select_db("MiDB");


mssql_query("TRUNCATE TABLE Cola");
$t1=time();
$query="BULK INSERT Cola
FROM 'C:\\www\\pruebas\\envio.txt'
WITH
(
KEEPNULLS,
FIELDTERMINATOR = '|',
ROWTERMINATOR = '\r\n'
)";
$i=0;
$fecha=date();
while ($i < MAX){
$str=null;
while ($j < TAM_BLOQUE && $i<=MAX){
$str.="0|0|".(620000000+$i)."|".$fecha."||2|12|8|1|1|un texto mas o menos largo|hola|prueba|10|http://www.google.com|1|1|0|0|0|0|0|0|0||\r\n";
$i++;$j++;
}
$fd=fopen("envio.txt","w");
fwrite($fd,$str);
fclose($fd);
mssql_query($query);
}
$t2=time();
echo "Tiempo: ".($t2-$t1);


Como se puede observar hay dos bucles anidados para evitar hacer todo el trabajo de golpe en caso de que se superen ciertos límites. Esto es así porque durante las pruebas observe que el uso de CPU se sostenía cerca del 100% durante bastante tiempo si se mandaba un sólo archivo de golpe. Escribir varios archivos le daba oxígeno al servidor y no me hacía perder un tiempo considerable en la ejecución total del script.

Sin duda el hecho de que el Apache pudiese escribir en el disco duro que comparte con el SQL Server aceleró bastante las cosas, pero esto puede hacer que a muchos de vosotros no os sirva la solución. Si no es vuestro caso tal vez podáis montar una unidad lógica para obtener unas condiciones parecidas pero sufriréis una latencia adicional por ello (aclaro que yo no he probado esto último).


Para los más curiosos detallaré un poco el entorno de pruebas que utilicé: se trata de un servidor con un procesador Intel Pentium 4 a 2,66 GHz con 1 GB de RAM y SQL Server 2000.

Os recuerdo algo que dejé caer en el anterior post y que es la moraleja de todo esto: no os fiéis de nada que encontréis en un blog, el blogger no tiene por que ser un gurú aunque él mismo lo crea. Por supuesto que este artículo está incluido en la moraleja así que si os interesa ponedlo en duda y haced vuestras propias pruebas antes de darlo por bueno.

No hay comentarios: