Verificar si una tablatiene datos ...

29/10/2007 - 20:36 por Peni | Informe spam
Que es más rápido en general, hacer un select count(*)... where o un
select top 1 ... where?


=Saludos. Peni.
=

Preguntas similare

Leer las respuestas

#36 jeastman - Hotmail
30/10/2007 - 21:36 | Informe spam
Peni, lo que sucede fue que te equivocaste de nombre


De todas formas Leonardo tiene razón en que quizás debo buscar más antes
de preguntar, intentaré seguir su consejo







Fue Alejandro Mesa quien te dio el consejo y no Leonardo Azpurua.


"Peni" escribió en el mensaje
news:
Te referiste a probar ... casi lo mismo, probar, buscar ... Creeme si te
digo que he gastado un montón de tiempo buscando en Google, pero hay cosas
que quiero hacer bien desde el principio y el rendimiento me preocupa
bastante. El problema que tengo es que solo recibí un curso muy básico de
SQL y como es lo primero un poco serio que hago en SQL, quizás quiero
abarcar demasiado en poco tiempo y en cuanto me encuentro con un problema
me desespero. Yo estaba acostumbrado al querido/odiado Access y SQL me
supone un cambio de mentalidad enorme y, como bien dices, los BOL no me
solucionan mucho, me resulta sumamente difícil encontrar lo que quiero,me
resultaba muchísimo más cómoda la ayuda de VB6, por ejemplo.

"Peni" escribió en el mensaje
news:
Estoy empezando a hacer cosas más o menos "de verdad" con SQL, así que
por aquí seguiré. En los pocos días que ando por aquí me he divertido un
montón leyendo estupendos hilos :-) De todas formas Leonardo tiene razón
en que quizás debo buscar más antes de preguntar, intentaré seguir su
consejo



Yo nunca dije eso...

De hecho, nunca miro los BOL (salvo la referencia de T/SQL o a menos que
no quede más remedio); algo en ellos me produce una especie de alergia en
el sistema cognitivo.

Salud!




=> Saludos. Peni.
=>

Respuesta Responder a este mensaje
#37 Eladio Rincón
30/10/2007 - 22:23 | Informe spam
hola,
voy a aportar mi granito de arena a ver si sirve de algo :)

En principio quería responder a la pequeña diferencia de tiempos entre 0 y
43 milisegundos y esas cosas; en esos casos, prefiero mirar el plan de
ejecución, e intentar entender los métodos de acceso que elige SQL Server.


En esa línea, viendo los planes de ejecución, podría decir que el grupo de
consultas se agrupan en dos tipos de soluciones:
1) las que necesitan recorrerse la tabla entera.
1 count(*) (4080) milisegundos
2 select 1 (7156) milisegundos
3 "if (select count(*)...) > 0 (4033) milisegundos" (esta la pongo entre
comillas por algo que comento luego)



2) las que con un pequeño acceso a la tabla pueden dar por satisfecha la
consulta.
4 select top 1 * (13) milisegundos
5 select top 1 1 (0) milisegundos
6 if exists (select *... (16) milisegundos
7 if exists (select 1... (0) milisegundos




1-1, count(*) --> recorrer toda la tabla para contar.
1-2, aunque no necesitas el valor de ninguna columna concreta, devolverá una
lista de 1.
1-3, necesita contar cuantas filas hay para satisfacer la condición IF.

2-4, top --> al encontrar 1 se finaliza la búsqueda.
2-5, top --> al encontrar 1 se finaliza la búsqueda.
2-6, en cuanto haya alguna que satisface la condición finaliza la búsqueda.
2-7, en cuanto haya alguna que satisface la condición finaliza la búsqueda.


bajo estas condiciones, concluiríamos que las del grupo 2 serán más
eficientes que las del grupo 1, si darle "demasiada" importancia a esos
milisegundos de diferencia.



También quería comentar finalmente que la consulta :
if (select count(*) from dbo.Orders ) > 0
print 'tiene filas'
else print 'NO tiene filas'

Tiene un comportamiento diferente entre SQL2000, y 2005.

en SQL 2000, para satisfacer la condición, primero cuenta todas las filas
que hay, y luego realiza la comparación.

en SQL 2005, para satisfacer la condición, el optimizador sabe que estás
haciendo un Exists :), de esta forma, la tendríamos que poner en el grupo 2)
:)

Lo he probado en 2000 SP4, 2005 RTM, y 2005 SP2, y su comportamiento es
consistente.

el comportamiento es igual para todas las comparaciones que se hagan con el
escalar 0; en cuanto le pongas una comparación de un valor distinto de 0,
como por ejemplo:
if (select count(*) from dbo.Orders ) = 1, o
if (select count(*) from dbo.Orders ) > 1, o
if (select count(*) from dbo.Orders ) > 10

El optimizador no lo resuelve y se tendrá que patear la tabla entera... :)


Podéis comprobarlo fácilmente viendo los planes de ejecución estimados, en
estos casos concretos, el truco será ver el número de filas estimadas que
devuelve el acceso a la tabla: en unos casos serán todas las filas (el caso
ineficiente), y en otros casos sólo una fila (la que le vale con la
validación de "existencia")


Saludos,

Eladio Rincón,
SQL Server MVP
http://blogs.solidq.com/es/elrincondeldba

"jeastman - Hotmail" wrote in message
news:
Señores.

Me tomé la libertad de hacer la prueba que sugiere el compañero José
Mariano, para ello creé una tabla con 2.342.560 de registros y sin ningún
indice primero y luego con un índice clustered, las pruebas las hice en el
mismo orden que las mostró el compañero y los resultados fueron los
siguiente:


SIN ÍNDICES
=> count(*) (4080) milisegundos
select 1 (7156) milisegundos
select top 1 * (13) milisegundos
select top 1 1 (0) milisegundos
if exists (select *... (16) milisegundos
if exists (select 1... (0) milisegundos
if (select count(*)...) > 0 (4033) milisegundos


CON ÍNDICE CLUSTERED
==> count(*) (10923) milisegundos
select 1 (12310) milisegundos
select top 1 * (46) milisegundos
select top 1 1 (0) milisegundos
if exists (select *... (13) milisegundos
if exists (select 1... (0) milisegundos
if (select count(*)...) > 0 (11690) milisegundos

Los resultados demuestran que existen dos opciones que supera a cualquier
otra con o sin índices

1) select top 1 1 (0) milisegundos
2) if exists(select 1 from aaa ) print 'tiene filas' else print 'NO tiene
filas'

Aqui les anexo el script que utilicé para la prueba

Saludos a todos.


P.D. Si alguien obtiene algún resultado diferente, me gustaría conocer los
resultados.

Este es el script de la tabla
CREATE TABLE aaa (
CorrelMovimiento int NOT NULL ,
CodEstructura int NOT NULL ,
CodPartida int NOT NULL ,
CodUsuario int NOT NULL ,
NroPresupuesto int NOT NULL ,
TipoMovimiento tinyint NOT NULL ,
PresupuestoOrd money NOT NULL ,
FIDES money NOT NULL ,
LAES money NOT NULL ,
Otras money NOT NULL ,
Observacion varchar (255) NOT NULL ,
FechaAgregado datetime NOT NULL ,
FechaCierre datetime NOT NULL
)


y el índice lo hice por los campos correlMovimiento y nroPresupuesto,
estaba seguro que podía hacer un índice único por esos valores


y el íindice lo hice
> declare @inicio datetime,
@fin datetime,
@dif int



DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select count(*) from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'count(*) (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select 1 from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'select 1 (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select top 1 * from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'select top 1 * (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select top 1 1 from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'select top 1 1 (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
if exists(select * from aaa ) print 'tiene filas' else
print 'NO tiene filas'
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'if exists (select *... (' + cast( @dif as varchar ) + ')
milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
if exists(select 1 from aaa ) print 'tiene filas' else
print 'NO tiene filas'
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'if exists (select 1... (' + cast( @dif as varchar ) + ')
milisegundos'


DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
if (select count(*) from aaa ) > 0 print 'tiene filas'
else print 'NO tiene filas'
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'if (select count(*)...) > 0 (' + cast( @dif as varchar ) + ')
milisegundos'
>

"Jose Mariano Alvarez"
escribió en el
mensaje news:e%
Los dos son igualmente malos.
Es mejor como dice alejandro, usando TOP 1 o usando el cuantificador
existencial.

Prueba esto con la base de datos de ejemplo y mira los pesos relativos.

select count(*) from dbo.FactInternetSales
select 1 from dbo.FactInternetSales
select top 1 * from dbo.FactInternetSales
select top 1 1 from dbo.FactInternetSales
if exists(select * from dbo.FactInternetSales ) print 'tiene filas' else
print 'NO tiene filas'
if exists(select 1 from dbo.FactInternetSales ) print 'tiene filas' else
print 'NO tiene filas'
if (select count(*) from dbo.FactInternetSales ) > 0 print 'tiene filas'
else print 'NO tiene filas'



Saludos
Ing. Jose Mariano Alvarez


(Cambia los ceros por O y saca lo que sobra)


IMPORTANTE

Por favor traten de indicar la versión de SQL y Service Pack.
La inclusión de (CREATE, INSERTS, etc.) para poder reproducir el problema
también ayuda.



"jeastman - Hotmail" wrote in message
news:e%238$
Hola.

Yo hice una prueba con éstas dos versiones:

select count(*) from tabla

y la segunda versión fue:

if exists (select 1 from tabla)
begin
print 'Existe'
end

La tabla es muy pequeña, solo tiene 73.205 registros

En la primera forma me dio un segundo, en la segunda no llegó al
segundo.

Yo personalmente utilizo la segunda alternativa, pues le dejo el trabajo
al obtimizador de buscar la mejor manera de averiguar si hay o no
registros, el 1 que está en el select es para evitar colocar un * que en
éste caso no hace falta.

Si obtienen otros resultados y alguna mejor vía me gustaría conocerla y
así evitarle trabajo al motor.

Saludos.

"Leonardo Azpurua" <l e o n a r d o [arroba] m v p s [punto] o r g>
escribió en el mensaje news:

"Penta" escribió en el mensaje
news:
Con el top de toda maneras, si haces un count(*) de una tabla de
muchos registros = se toma su tiempo.



Igual hay quien sabe mas que nosotros de SQL Server y me corrige, pero
creo que el COUNT(*) lo unico que hace es examinar el descriptor de la
tabla, o sea que debe ser mucho más rápido.

Salud!














Respuesta Responder a este mensaje
#38 jeastman - Hotmail
30/10/2007 - 23:11 | Informe spam
Hola Eladio.

De verdad no tengo instalado el SQL 2k5, así que tu comentario es muy
oportuno para cuando llegue el momento.

Creo que ya no tedré que ejecutar el script en esa versión, ;-)

Gracias por unirte y aportar a ésta interesante discución.

Saludos.

"Eladio Rincón" escribió en el mensaje
news:
hola,
voy a aportar mi granito de arena a ver si sirve de algo :)

En principio quería responder a la pequeña diferencia de tiempos entre 0 y
43 milisegundos y esas cosas; en esos casos, prefiero mirar el plan de
ejecución, e intentar entender los métodos de acceso que elige SQL Server.


En esa línea, viendo los planes de ejecución, podría decir que el grupo de
consultas se agrupan en dos tipos de soluciones:
1) las que necesitan recorrerse la tabla entera.
1 count(*) (4080) milisegundos
2 select 1 (7156) milisegundos
3 "if (select count(*)...) > 0 (4033) milisegundos" (esta la pongo entre
comillas por algo que comento luego)



2) las que con un pequeño acceso a la tabla pueden dar por satisfecha la
consulta.
4 select top 1 * (13) milisegundos
5 select top 1 1 (0) milisegundos
6 if exists (select *... (16) milisegundos
7 if exists (select 1... (0) milisegundos




1-1, count(*) --> recorrer toda la tabla para contar.
1-2, aunque no necesitas el valor de ninguna columna concreta, devolverá
una lista de 1.
1-3, necesita contar cuantas filas hay para satisfacer la condición IF.

2-4, top --> al encontrar 1 se finaliza la búsqueda.
2-5, top --> al encontrar 1 se finaliza la búsqueda.
2-6, en cuanto haya alguna que satisface la condición finaliza la
búsqueda.
2-7, en cuanto haya alguna que satisface la condición finaliza la
búsqueda.


bajo estas condiciones, concluiríamos que las del grupo 2 serán más
eficientes que las del grupo 1, si darle "demasiada" importancia a esos
milisegundos de diferencia.



También quería comentar finalmente que la consulta :
if (select count(*) from dbo.Orders ) > 0
print 'tiene filas'
else print 'NO tiene filas'

Tiene un comportamiento diferente entre SQL2000, y 2005.

en SQL 2000, para satisfacer la condición, primero cuenta todas las filas
que hay, y luego realiza la comparación.

en SQL 2005, para satisfacer la condición, el optimizador sabe que estás
haciendo un Exists :), de esta forma, la tendríamos que poner en el grupo
2) :)

Lo he probado en 2000 SP4, 2005 RTM, y 2005 SP2, y su comportamiento es
consistente.

el comportamiento es igual para todas las comparaciones que se hagan con
el escalar 0; en cuanto le pongas una comparación de un valor distinto de
0, como por ejemplo:
if (select count(*) from dbo.Orders ) = 1, o
if (select count(*) from dbo.Orders ) > 1, o
if (select count(*) from dbo.Orders ) > 10

El optimizador no lo resuelve y se tendrá que patear la tabla entera... :)


Podéis comprobarlo fácilmente viendo los planes de ejecución estimados, en
estos casos concretos, el truco será ver el número de filas estimadas que
devuelve el acceso a la tabla: en unos casos serán todas las filas (el
caso ineficiente), y en otros casos sólo una fila (la que le vale con la
validación de "existencia")


Saludos,

Eladio Rincón,
SQL Server MVP
http://blogs.solidq.com/es/elrincondeldba

"jeastman - Hotmail" wrote in message
news:
Señores.

Me tomé la libertad de hacer la prueba que sugiere el compañero José
Mariano, para ello creé una tabla con 2.342.560 de registros y sin ningún
indice primero y luego con un índice clustered, las pruebas las hice en
el mismo orden que las mostró el compañero y los resultados fueron los
siguiente:


SIN ÍNDICES
=>> count(*) (4080) milisegundos
select 1 (7156) milisegundos
select top 1 * (13) milisegundos
select top 1 1 (0) milisegundos
if exists (select *... (16) milisegundos
if exists (select 1... (0) milisegundos
if (select count(*)...) > 0 (4033) milisegundos


CON ÍNDICE CLUSTERED
==>> count(*) (10923) milisegundos
select 1 (12310) milisegundos
select top 1 * (46) milisegundos
select top 1 1 (0) milisegundos
if exists (select *... (13) milisegundos
if exists (select 1... (0) milisegundos
if (select count(*)...) > 0 (11690) milisegundos

Los resultados demuestran que existen dos opciones que supera a cualquier
otra con o sin índices

1) select top 1 1 (0) milisegundos
2) if exists(select 1 from aaa ) print 'tiene filas' else print 'NO tiene
filas'

Aqui les anexo el script que utilicé para la prueba

Saludos a todos.


P.D. Si alguien obtiene algún resultado diferente, me gustaría conocer
los resultados.

Este es el script de la tabla
CREATE TABLE aaa (
CorrelMovimiento int NOT NULL ,
CodEstructura int NOT NULL ,
CodPartida int NOT NULL ,
CodUsuario int NOT NULL ,
NroPresupuesto int NOT NULL ,
TipoMovimiento tinyint NOT NULL ,
PresupuestoOrd money NOT NULL ,
FIDES money NOT NULL ,
LAES money NOT NULL ,
Otras money NOT NULL ,
Observacion varchar (255) NOT NULL ,
FechaAgregado datetime NOT NULL ,
FechaCierre datetime NOT NULL
)


y el índice lo hice por los campos correlMovimiento y nroPresupuesto,
estaba seguro que podía hacer un índice único por esos valores


y el íindice lo hice
>> declare @inicio datetime,
@fin datetime,
@dif int



DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select count(*) from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'count(*) (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select 1 from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'select 1 (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select top 1 * from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'select top 1 * (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
select top 1 1 from aaa
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'select top 1 1 (' + cast( @dif as varchar ) + ') milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
if exists(select * from aaa ) print 'tiene filas' else
print 'NO tiene filas'
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'if exists (select *... (' + cast( @dif as varchar ) + ')
milisegundos'

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
if exists(select 1 from aaa ) print 'tiene filas' else
print 'NO tiene filas'
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'if exists (select 1... (' + cast( @dif as varchar ) + ')
milisegundos'


DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
set @inicio = getdate()
if (select count(*) from aaa ) > 0 print 'tiene filas'
else print 'NO tiene filas'
set @fin = getdate()
set @dif = datediff( ms, @inicio, @fin )
print 'if (select count(*)...) > 0 (' + cast( @dif as varchar ) + ')
milisegundos'
>>

"Jose Mariano Alvarez"
escribió en el
mensaje news:e%
Los dos son igualmente malos.
Es mejor como dice alejandro, usando TOP 1 o usando el cuantificador
existencial.

Prueba esto con la base de datos de ejemplo y mira los pesos relativos.

select count(*) from dbo.FactInternetSales
select 1 from dbo.FactInternetSales
select top 1 * from dbo.FactInternetSales
select top 1 1 from dbo.FactInternetSales
if exists(select * from dbo.FactInternetSales ) print 'tiene filas' else
print 'NO tiene filas'
if exists(select 1 from dbo.FactInternetSales ) print 'tiene filas' else
print 'NO tiene filas'
if (select count(*) from dbo.FactInternetSales ) > 0 print 'tiene filas'
else print 'NO tiene filas'



Saludos
Ing. Jose Mariano Alvarez


(Cambia los ceros por O y saca lo que sobra)


IMPORTANTE

Por favor traten de indicar la versión de SQL y Service Pack.
La inclusión de (CREATE, INSERTS, etc.) para poder reproducir el
problema también ayuda.



"jeastman - Hotmail" wrote in message
news:e%238$
Hola.

Yo hice una prueba con éstas dos versiones:

select count(*) from tabla

y la segunda versión fue:

if exists (select 1 from tabla)
begin
print 'Existe'
end

La tabla es muy pequeña, solo tiene 73.205 registros

En la primera forma me dio un segundo, en la segunda no llegó al
segundo.

Yo personalmente utilizo la segunda alternativa, pues le dejo el
trabajo al obtimizador de buscar la mejor manera de averiguar si hay o
no registros, el 1 que está en el select es para evitar colocar un *
que en éste caso no hace falta.

Si obtienen otros resultados y alguna mejor vía me gustaría conocerla
y así evitarle trabajo al motor.

Saludos.

"Leonardo Azpurua" <l e o n a r d o [arroba] m v p s [punto] o r g>
escribió en el mensaje news:

"Penta" escribió en el mensaje
news:
Con el top de toda maneras, si haces un count(*) de una tabla de
muchos registros = se toma su tiempo.



Igual hay quien sabe mas que nosotros de SQL Server y me corrige, pero
creo que el COUNT(*) lo unico que hace es examinar el descriptor de la
tabla, o sea que debe ser mucho más rápido.

Salud!


















Respuesta Responder a este mensaje
#39 Peni
31/10/2007 - 07:22 | Informe spam
Aissss ... tengo que ver más la televisión y trabajar menos :-)

Peni, lo que sucede fue que te equivocaste de nombre


De todas formas Leonardo tiene razón en que quizás debo buscar más antes
de preguntar, intentaré seguir su consejo







Fue Alejandro Mesa quien te dio el consejo y no Leonardo Azpurua.


"Peni" escribió en el mensaje
news:
Te referiste a probar ... casi lo mismo, probar, buscar ... Creeme si te
digo que he gastado un montón de tiempo buscando en Google, pero hay cosas
que quiero hacer bien desde el principio y el rendimiento me preocupa
bastante. El problema que tengo es que solo recibí un curso muy básico de
SQL y como es lo primero un poco serio que hago en SQL, quizás quiero
abarcar demasiado en poco tiempo y en cuanto me encuentro con un problema
me desespero. Yo estaba acostumbrado al querido/odiado Access y SQL me
supone un cambio de mentalidad enorme y, como bien dices, los BOL no me
solucionan mucho, me resulta sumamente difícil encontrar lo que quiero,me
resultaba muchísimo más cómoda la ayuda de VB6, por ejemplo.

"Peni" escribió en el mensaje
news:
Estoy empezando a hacer cosas más o menos "de verdad" con SQL, así que
por aquí seguiré. En los pocos días que ando por aquí me he divertido un
montón leyendo estupendos hilos :-) De todas formas Leonardo tiene razón
en que quizás debo buscar más antes de preguntar, intentaré seguir su
consejo



Yo nunca dije eso...

De hecho, nunca miro los BOL (salvo la referencia de T/SQL o a menos que
no quede más remedio); algo en ellos me produce una especie de alergia en
el sistema cognitivo.

Salud!




=>> Saludos. Peni.
=>>







=Saludos. Peni.
=
Respuesta Responder a este mensaje
#40 Penta
31/10/2007 - 15:13 | Informe spam
En definitiva nos quedamos con el Select top 1 from tabla ???

Salu2.
Penta.
Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida