Solía escribir mis cheques EXISTS como este:
IF EXISTS (SELECT * FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Where Columns=@Filters
END
Uno de los DBA en una vida anterior me dijo que cuando hago una EXISTS
cláusula, use en SELECT 1
lugar deSELECT *
IF EXISTS (SELECT 1 FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Columns=@Filters
END
¿Esto realmente hace una diferencia?
sql
sql-server
tsql
Raj Más
fuente
fuente
Respuestas:
No, SQL Server es inteligente y sabe que se está utilizando para un EXISTS y no devuelve NINGÚN DATO al sistema.
Dijo Microsoft: http://technet.microsoft.com/en-us/library/ms189259.aspx?ppud=4
Para comprobarlo, intente ejecutar lo siguiente:
SELECT whatever FROM yourtable WHERE EXISTS( SELECT 1/0 FROM someothertable WHERE a_valid_clause )
Si realmente estuviera haciendo algo con la lista SELECT, arrojaría un error div por cero. No es así.
EDITAR: Tenga en cuenta que el estándar SQL en realidad habla de esto.
Norma ANSI SQL 1992, pág. 191 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
fuente
EXISTS
truco con 1/0 se puede incluso extender a estoSELECT 1 WHERE EXISTS(SELECT 1/0)
... parece un paso más abstracto que el segundoSELECT
yaFROM
que no tiene cláusulaSELECT COUNT(*) WHERE EXISTS(SELECT 1/0)
. ASELECT
sin unFROM
en SQL Server se trata como si estuviera accediendo a una tabla de una sola fila (por ejemplo, similar a seleccionar de ladual
tabla en otros RDBMS)SELECT
crea una tabla de 1 fila antes de hacer cualquier otra cosa, así que, ¿a pesar de que todavía1/0
es basura la tabla de 1 filaEXISTS
?La razón de este error es presumiblemente la creencia de que terminará leyendo todas las columnas. Es fácil ver que este no es el caso.
CREATE TABLE T ( X INT PRIMARY KEY, Y INT, Z CHAR(8000) ) CREATE NONCLUSTERED INDEX NarrowIndex ON T(Y) IF EXISTS (SELECT * FROM T) PRINT 'Y'
Da plan
Esto muestra que SQL Server pudo usar el índice más estrecho disponible para verificar el resultado a pesar de que el índice no incluye todas las columnas. El acceso al índice está bajo un operador de semiunión, lo que significa que puede dejar de escanear tan pronto como se devuelva la primera fila.
Entonces, está claro que la creencia anterior es incorrecta.
Sin embargo, Conor Cunningham del equipo de Optimizador de consultas explica aquí que normalmente usa
SELECT 1
en este caso, ya que puede hacer una pequeña diferencia de rendimiento en la compilación de la consulta.Probé cuatro formas posibles de expresar esta consulta en una tabla vacía con varios números de columnas.
SELECT 1
vsSELECT *
vsSELECT Primary_Key
vsSELECT Other_Not_Null_Column
.Ejecuté las consultas en un bucle usando
OPTION (RECOMPILE)
y medí el número promedio de ejecuciones por segundo. Resultados abajo+-------------+----------+---------+---------+--------------+ | Num of Cols | * | 1 | PK | Not Null col | +-------------+----------+---------+---------+--------------+ | 2 | 2043.5 | 2043.25 | 2073.5 | 2067.5 | | 4 | 2038.75 | 2041.25 | 2067.5 | 2067.5 | | 8 | 2015.75 | 2017 | 2059.75 | 2059 | | 16 | 2005.75 | 2005.25 | 2025.25 | 2035.75 | | 32 | 1963.25 | 1967.25 | 2001.25 | 1992.75 | | 64 | 1903 | 1904 | 1936.25 | 1939.75 | | 128 | 1778.75 | 1779.75 | 1799 | 1806.75 | | 256 | 1530.75 | 1526.5 | 1542.75 | 1541.25 | | 512 | 1195 | 1189.75 | 1203.75 | 1198.5 | | 1024 | 694.75 | 697 | 699 | 699.25 | +-------------+----------+---------+---------+--------------+ | Total | 17169.25 | 17171 | 17408 | 17408 | +-------------+----------+---------+---------+--------------+
Como puede verse, no hay un ganador consistente entre
SELECT 1
ySELECT *
y la diferencia entre los dos enfoques es insignificante. Sin embargo, elSELECT Not Null col
ySELECT PK
parece un poco más rápido.Las cuatro consultas degradan su rendimiento a medida que aumenta el número de columnas de la tabla.
Como la tabla está vacía, esta relación solo parece explicable por la cantidad de metadatos de columna. Porque
COUNT(1)
es fácil ver que esto se reescribeCOUNT(*)
en algún punto del proceso desde abajo.SET SHOWPLAN_TEXT ON; GO SELECT COUNT(1) FROM master..spt_values
Lo que da el siguiente plan
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1004],0))) |--Stream Aggregate(DEFINE:([Expr1004]=Count(*))) |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))
Adjuntar un depurador al proceso de SQL Server y romper aleatoriamente mientras se ejecuta lo siguiente
DECLARE @V int WHILE (1=1) SELECT @V=1 WHERE EXISTS (SELECT 1 FROM ##T) OPTION(RECOMPILE)
Descubrí que en los casos en los que la tabla tiene 1024 columnas la mayor parte del tiempo, la pila de llamadas se parece a lo que se muestra a continuación, lo que indica que, de hecho, está gastando una gran proporción del tiempo cargando metadatos de la columna incluso cuando
SELECT 1
se usa (para el caso en que el la tabla tiene 1 columna que se rompe aleatoriamente no golpeó esta parte de la pila de llamadas en 10 intentos)Este intento de creación de perfiles manual está respaldado por el generador de perfiles de código VS 2012, que muestra una selección muy diferente de funciones que consumen tiempo de compilación para los dos casos (las 15 columnas principales de 1024 funciones frente a las 15 funciones principales 1 columna ).
Tanto el
SELECT 1
ySELECT *
versiones terminan verificación de los permisos de columna y un error si el usuario no tiene acceso a todas las columnas de la tabla.Un ejemplo que tomé de una conversación en el montón
CREATE USER blat WITHOUT LOGIN; GO CREATE TABLE dbo.T ( X INT PRIMARY KEY, Y INT, Z CHAR(8000) ) GO GRANT SELECT ON dbo.T TO blat; DENY SELECT ON dbo.T(Z) TO blat; GO EXECUTE AS USER = 'blat'; GO SELECT 1 WHERE EXISTS (SELECT 1 FROM T); /* ↑↑↑↑ Fails unexpectedly with The SELECT permission was denied on the column 'Z' of the object 'T', database 'tempdb', schema 'dbo'.*/ GO REVERT; DROP USER blat DROP TABLE T
Entonces, uno podría especular que la menor diferencia aparente al usar
SELECT some_not_null_col
es que solo termina verificando los permisos en esa columna específica (aunque todavía carga los metadatos para todos). Sin embargo, esto no parece encajar con los hechos, ya que la diferencia porcentual entre los dos enfoques, si es que algo se reduce a medida que aumenta el número de columnas en la tabla subyacente.En cualquier caso, no me apresuraré a cambiar todas mis consultas a este formulario, ya que la diferencia es muy pequeña y solo es evidente durante la compilación de consultas. La eliminación de
OPTION (RECOMPILE)
para que las ejecuciones posteriores puedan usar un plan almacenado en caché proporcionó lo siguiente.+-------------+-----------+------------+-----------+--------------+ | Num of Cols | * | 1 | PK | Not Null col | +-------------+-----------+------------+-----------+--------------+ | 2 | 144933.25 | 145292 | 146029.25 | 143973.5 | | 4 | 146084 | 146633.5 | 146018.75 | 146581.25 | | 8 | 143145.25 | 144393.25 | 145723.5 | 144790.25 | | 16 | 145191.75 | 145174 | 144755.5 | 146666.75 | | 32 | 144624 | 145483.75 | 143531 | 145366.25 | | 64 | 145459.25 | 146175.75 | 147174.25 | 146622.5 | | 128 | 145625.75 | 143823.25 | 144132 | 144739.25 | | 256 | 145380.75 | 147224 | 146203.25 | 147078.75 | | 512 | 146045 | 145609.25 | 145149.25 | 144335.5 | | 1024 | 148280 | 148076 | 145593.25 | 146534.75 | +-------------+-----------+------------+-----------+--------------+ | Total | 1454769 | 1457884.75 | 1454310 | 1456688.75 | +-------------+-----------+------------+-----------+--------------+
El script de prueba que utilicé se puede encontrar aquí.
fuente
La mejor manera de saberlo es probar el rendimiento de ambas versiones y consultar el plan de ejecución para ambas versiones. Elija una tabla con muchas columnas.
fuente
No hay diferencia en SQL Server y nunca ha sido un problema en SQL Server. El optimizador sabe que son iguales. Si observa los planes de ejecución, verá que son idénticos.
fuente
Personalmente, me resulta muy, muy difícil de creer que no optimicen el mismo plan de consulta. Pero la única forma de saberlo en su situación particular es probarlo. Si es así, ¡infórmanos!
fuente
No hay ninguna diferencia real, pero puede haber un impacto muy pequeño en el rendimiento. Como regla general, no debe solicitar más datos de los que necesita.
fuente