Consulta eficiente de prueba SQL o consulta de validación que funcionará en todas (o la mayoría) de las bases de datos

148

Muchas bibliotecas de agrupación de conexiones de bases de datos proporcionan la capacidad de probar sus conexiones SQL en busca de inactividad. Por ejemplo, la biblioteca de agrupación JDBC c3p0 tiene una propiedad llamada preferredTestQuery, que se ejecuta en la conexión a intervalos configurados. Del mismo modo, Apache Commons DBCP tiene validationQuery.

Muchas consultas de ejemplo que he visto son para MySQL y recomiendo usarlas como el valor para la consulta de prueba. Sin embargo, esta consulta no funciona en algunas bases de datos (por ejemplo, HSQLDB, para lo cual se espera una cláusula).SELECT 1;SELECT 1FROM

¿Existe una consulta independiente de la base de datos que sea igualmente eficiente pero funcione para todas las bases de datos SQL?

Editar:

Si no existe (que parece ser el caso), ¿alguien puede sugerir un conjunto de consultas SQL que funcionarán para varios proveedores de bases de datos? Mi intención sería determinar mediante programación una declaración que pueda usar según la configuración de mi proveedor de base de datos.

Rob Hruska
fuente
1
Consulte también Consulta simple de DB2 para la validación de la conexión .
dma_k
1
Nota: ya no es necesario configurar una consulta de prueba, vea mi respuesta a continuación
Tim Büthe,

Respuestas:

274

Después de un poco de investigación junto con la ayuda de algunas de las respuestas aquí:

SELECT 1

  • H2
  • MySQL
  • Microsoft SQL Server (según NimChimpsky )
  • PostgreSQL
  • SQLite

SELECT 1 FROM DUAL

  • Oráculo

SELECT 1 FROM any_existing_table WHERE 1=0

o

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB (probado con la versión 1.8.0.10)

    Nota: Intenté usar una WHERE 1=0cláusula en la segunda consulta, pero no funcionó como un valor para los DBCP de Apache Commons validationQuery, ya que la consulta no devuelve ninguna fila


VALUES 1 o SELECT 1 FROM SYSIBM.SYSDUMMY1

  • Apache Derby (a través de daiscog )

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix
Rob Hruska
fuente
Debería ser "SELECT 1 FROM any_existing_table WHERE 1 = 0"; de lo contrario, la llamada podría ser muy lenta. Por cierto, tanto SELECT 1 como SELECT 1 FROM DUAL también funcionan con H2.
Thomas Mueller
2
Sé que esto tiene un par de años, pero es posible que desee agregar ambos VALUES 1y SELECT 1 FROM SYSIBM.SYSDUMMY1para Apache Derby
daiscog
Suponiendo que OP quiere una respuesta Java: creo que con Java 6 esta respuesta ahora está desactualizada. Vea mi respuesta en otra parte de esta página.
Peter
Puede agregar estos dos a su respuesta, DB2: "SELECCIONE la fecha actual DESDE sysibm.sysdummy1" Informix: "seleccione recuento (*) de sílabas"
Michael
@Michael Si desea sugerir una edición, la aprobaría. Además, obtendrás un par de puntos de repetición por ello.
Rob Hruska
22

Si su controlador es compatible con JDBC 4, no hay necesidad de una consulta dedicada para probar las conexiones. En cambio, hay Connection.isValid para probar la conexión.

¡JDBC 4 es parte de Java 6 desde 2006 y su controlador ya debería ser compatible con esto!

Los grupos de conexiones famosos, como HikariCP, todavía tienen un parámetro de configuración para especificar una consulta de prueba, pero desaconsejamos utilizarlo:

🔠connectionTestQuery

Si su controlador admite JDBC4, le recomendamos encarecidamente que no configure esta propiedad. Esto es para bases de datos "heredadas" que no son compatibles con la API JDBC4 Connection.isValid (). Esta es la consulta que se ejecutará justo antes de que se le proporcione una conexión desde el grupo para validar que la conexión a la base de datos aún está activa. Nuevamente, intente ejecutar el grupo sin esta propiedad, HikariCP registrará un error si su controlador no es compatible con JDBC4 para informarle. Predeterminado: ninguno

Tim Büthe
fuente
9

Desafortunadamente, no hay una instrucción SELECT que siempre funcione independientemente de la base de datos.

La mayoría de las bases de datos son compatibles:

SELECT 1

Algunas bases de datos no admiten esto, pero tienen una tabla llamada DUAL que puede usar cuando no necesita una tabla:

SELECT 1 FROM DUAL

MySQL también admite esto por razones de compatibilidad, pero no todas las bases de datos lo hacen. Una solución alternativa para las bases de datos que no admiten ninguno de los anteriores es crear una tabla llamada DUAL que contenga una sola fila, entonces lo anterior funcionará.

HSQLDB no admite ninguno de los anteriores, por lo que puede crear la tabla DUAL o usar:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database
Mark Byers
fuente
Gracias por la respuesta. He actualizado ligeramente mi pregunta debido a su declaración "no hay una declaración SELECT que siempre funcionará". SELECT 1 FROM DUALtampoco funciona con HSQLDB.
Rob Hruska
1
+1, aquí es donde también he venido con mi investigación, particularmente para el caso HSQLDB.
Rob Hruska
¿cuáles no son compatibles con "seleccione 1"? Seleccione de dual solo funciona oracle ¿no? No es servidor SQL, o MySQL al menos
NimChimpsky
+1 ¡He dejado de intentar pensar en una forma independiente de RDBMS!
Martin Smith
2

Yo uso este:

select max(table_catalog) as x from information_schema.tables

para verificar la conexión y la capacidad de ejecutar consultas (con 1 fila como resultado) para postgreSQL, MySQL y MSSQL.

Wojciechk
fuente
2

yo suelo

Select COUNT(*) As X From INFORMATION_SCHEMA.SYSTEM_USERS Where 1=0

para hsqldb 1.8.0

thinkbase
fuente
2

Para el uso de pruebas select count(*), debería ser más eficiente de usar select count(1)porque *puede hacer que lea todos los datos de la columna.

Nathan Niesen
fuente
1

select 1 funcionaría en el servidor sql, no estoy seguro acerca de los demás.

Use ansi sql estándar para crear una tabla y luego consulte desde esa tabla.

NimChimpsky
fuente
¿Ansi SQL cubre create table?
Martin Smith
si lo hace Si usa tipos de datos ansi. Sin embargo, me sorprendería si "select 1" no funcionara.
NimChimpsky
1

Asumiendo que el OP quiere una respuesta Java:

A partir de JDBC3 / Java 6 está el isValid () método que debería usarse en lugar de inventar el propio método.

Se requiere que el implementador del controlador ejecute algún tipo de consulta en la base de datos cuando se llama a este ID de método. Usted, como simple usuario de JDBC, no tiene que saber ni comprender qué es esta consulta. Todo lo que tiene que hacer es confiar en que el creador del controlador JDBC ha hecho su trabajo correctamente.

Peter
fuente
2
Creo que el OP está hablando de una consulta de validación para la configuración del grupo de conexiones de un Contenedor, no programáticamente. Por ejemplo, en el archivo context.xml de Tomcat, donde configura Recursos, se necesita una validationQuery que Tomcat utiliza para validar una conexión. Tomcat en sí tendría que cambiarse para aprovechar isValid (). Eso no es algo que el OP pueda controlar.
Michael
También vale la pena señalar que "el creador del controlador JDBC ha hecho su trabajo correctamente" no está realmente garantizado. Acabo de descubrir que ni Postgres, HSQLDB ni H2 se molestaron en implementar el método, por lo que siempre generará una excepción allí.
akroy
1

Qué tal si

SELECT user()

Lo uso antes. MySQL, H2 está bien, no conozco a otros.

Wener
fuente
1

Me acabo de enterar por las malas que es

SELECT 1 FROM DUAL

para MaxDB también.

Lars Decker
fuente
Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente reputación , podrá comentar cualquier publicación ; en su lugar, proporcione respuestas que no requieran una aclaración del autor de la pregunta . - De la opinión
Peter Brittain
No lo entiendo, agrega valor a la respuesta aceptada, entonces, ¿dónde está el problema?
Lars Decker
Y como mencionó: como no puedo comentar la respuesta aceptada, la pongo aquí como respuesta. ¿Así que es mejor no escribir una publicación, aunque podría ser útil solo por falta de reputación?
Lars Decker
TBH, es una llamada cerrada ... En lugar de duplicar una respuesta, esto debería haber sido un comentario sobre la respuesta original. De lo contrario, podría haber hecho una edición sugerida al original.
Peter Brittain
1

Para Oracle, la consulta de alto rendimiento será

select 'X' from <your_small_table> where <primay_key_coulmn> = <some_value>

Esto es desde una perspectiva de rendimiento.

Joby Kurian
fuente
0

Yo uso esto para Firebird

select 1 from RDB$RELATION_FIELDS rows 1
claudsan
fuente
0

Para MSSQL .

Esto me ayudó a determinar si los servidores vinculados estaban vivos. Usando una conexión de consulta abierta y un TRY CATCH para poner los resultados del error en algo útil.

IF OBJECT_ID('TEMPDB..#TEST_CONNECTION') IS NOT NULL DROP TABLE #TEST_CONNECTION
IF OBJECT_ID('TEMPDB..#RESULTSERROR') IS NOT NULL DROP TABLE #RESULTSERROR
IF OBJECT_ID('TEMPDB..#RESULTSGOOD') IS NOT NULL DROP TABLE #RESULTSGOOD

DECLARE @LINKEDSERVER AS VARCHAR(25)    SET @LINKEDSERVER = 'SERVER NAME GOES HERE'
DECLARE @SQL AS VARCHAR(MAX)
DECLARE @OPENQUERY AS VARCHAR(MAX)

--IF OBJECT_ID ('dbo.usp_GetErrorInfo', 'P' ) IS NOT NULL DROP PROCEDURE usp_GetErrorInfo;  
--GO  

---- Create procedure to retrieve error information.  
--CREATE PROCEDURE dbo.usp_GetErrorInfo  
--AS  
--SELECT     
--    ERROR_NUMBER() AS ErrorNumber  
--    ,ERROR_SEVERITY() AS ErrorSeverity  
--    ,ERROR_STATE() AS ErrorState  
--    ,ERROR_PROCEDURE() AS ErrorProcedure  
--    ,ERROR_LINE() AS ErrorLine  
--    ,ERROR_MESSAGE() AS Message;  
--GO  


BEGIN TRY
SET @SQL='
SELECT 1 
'''
--SELECT @SQL
SET @OPENQUERY = 'SELECT * INTO ##TEST_CONNECTION FROM OPENQUERY(['+ @LINKEDSERVER +'],''' + @SQL + ')'
--SELECT @OPENQUERY
EXEC(@OPENQUERY)
SELECT * INTO #TEST_CONNECTION FROM ##TEST_CONNECTION
DROP TABLE ##TEST_CONNECTION
--SELECT * FROM #TEST_CONNECTION
END TRY

BEGIN CATCH
-- Execute error retrieval routine.
IF OBJECT_ID('dbo.usp_GetErrorInfo') IS NOT NULL -- IT WILL ALWAYS HAVE SOMTHING... 
    BEGIN
        CREATE TABLE #RESULTSERROR (
        [ErrorNumber]       INT
        ,[ErrorSeverity]    INT
        ,[ErrorState]       INT
        ,[ErrorProcedure]   INT
        ,[ErrorLine]        INT
        ,[Message]          NVARCHAR(MAX) 
        )
        INSERT INTO #RESULTSERROR
        EXECUTE dbo.usp_GetErrorInfo
    END
END CATCH

BEGIN 
    IF (Select ERRORNUMBER FROM #RESULTSERROR WHERE ERRORNUMBER = '1038') IS NOT NULL --'1038' FOR ME SHOWED A CONNECTION ATLEAST. 
        SELECT
        '0' AS [ErrorNumber]        
        ,'0'AS [ErrorSeverity]  
        ,'0'AS [ErrorState]     
        ,'0'AS [ErrorProcedure] 
        ,'0'AS [ErrorLine]      
        , CONCAT('CONNECTION IS UP ON ', @LINKEDSERVER) AS [Message]            
    ELSE 
        SELECT * FROM #RESULTSERROR
END

docs.microsoft.com

DeFlanko
fuente