martes, 2 de marzo de 2010

T-SQL: SET ROWCOUNT vs. SELECT TOP

“Si hay 2 formas de hacer lo mismo, una seguro que da problemas.”
No sé si esta es una de las Leyes de Murphy, pero debería serlo :P

SET ROWCOUNT es uno de esos settings “con trampa” que tiene T-SQL y que si no sabes usarlos adecuadamente te puede provocar muchos quebraderos de cabeza.

Según MSDN: Hace que SQL Server detenga el procesamiento de la consulta una vez que se han devuelto las filas especificadas.

Ah, qué bonito, si sólo quiero que una consulta me devuelva 20 registros pues pongo “SET ROWCOUNT 20;” antes de ejecutarla y listo.
Vamos, lo mismo que si hago un SELECT TOP 20 …

Bueno, sabiendo esto se puede elegir entre utilizar uno u otro método para limitar los resultados. Pero SET ROWCOUNT, al tratarse de un setting afecta a TODAS las consultas que se ejecutan dentro del mismo contexto y aquí es donde viene el problema.

Por ejemplo, supongamos que tenemos 2 tablas relacionadas y una función llamada MiFuncion() que hace lo siguiente:


SELECT idPadre FROM TablaPadre WHERE campoPadre = @parametro


Ahora bien, si hacemos esto:


SET ROWCOUNT 10;
SELECT * FROM TablaHija WHERE idPadre in (select idPadre from MiFuncion(@parametro))


La llamada a MiFuncion (@parametro) devolverá únicamente 10 registros, y a su vez la SELECT inicial también devolverá 10 registros, lo que puede provocar que no obtengamos el resultado deseado :(

¿Y cómo se puede solucionar esto? Pues es relativamente sencillo, cambiamos la llamada a la función por una subconsulta:


SET ROWCOUNT 10;
SELECT * FROM TablaHija WHERE idPadre in (SELECT idPadre FROM TablaPadre WHERE campoPadre = @parametro)


Y así, la subconsulta devuelve los registros que tenga que devolver, sin tener en cuenta el número de SET ROWCOUNT y la SELECT sí que devuelve 10 registros O_o El que lo entienda que me lo explique.

Así que ya sabéis, si vais a usar SET ROWCOUNT, hacerlo con cuidado y aseguraros de desactivarla usando SET ROWCOUNT 0. En cualquier caso, es menos peligroso usar SELECT TOP, ya que solo afecta a la consulta en la que se especifica.

Tampoco es muy aconsejable mezclar SELECT TOP … con SET ROWCOUNT … porque SET ROWCOUNT anula la palabra clave TOP de la instrucción SELECT si el número de filas es inferior.

Happy codding ;)

BOLA EXTRA: a partir de la próxima versión de SQL Server (la que siga a la 2008) la utilización de SET ROWCOUNT no afectará a las instrucciones DELETE, INSERT ni UPDATE.
No me quiero ni imaginar los problemas que puede provocar SET ROWCOUNT con un UPDATE O_o