Query di test SQL efficiente o query di convalida che funzionerà su tutti (o la maggior parte) dei database


148

Molte librerie di pool di connessioni al database offrono la possibilità di testare le proprie connessioni SQL per la pigrizia. Ad esempio, la libreria di pooling JDBC c3p0 ha una proprietà chiamata preferredTestQuery, che viene eseguita sulla connessione a intervalli configurati. Allo stesso modo, Apache Commons DBCP ha validationQuery.

Molte query di esempio che ho visto sono per MySQL e raccomandano di usare come valore per la query di prova. Tuttavia, questa query non funziona su alcuni database (ad esempio HSQLDB, per i quali si aspetta una clausola).SELECT 1;SELECT 1FROM

Esiste una query indipendente dal database che è altrettanto efficiente ma funzionerà per tutti i database SQL?

Modificare:

Se non c'è (che sembra essere il caso), qualcuno può suggerire una serie di query SQL che funzioneranno per vari provider di database? La mia intenzione sarebbe quella di determinare a livello di codice un'istruzione che posso usare in base alla configurazione del mio provider di database.



1
Nota: la configurazione di una query di prova non è più necessaria, vedere la mia risposta di seguito
Tim Büthe

Risposte:


274

Dopo un po 'di ricerca insieme all'aiuto di alcune delle risposte qui:

SELECT 1

  • H2
  • MySQL
  • Microsoft SQL Server (secondo NimChimpsky )
  • PostgreSQL
  • SQLite

SELECT 1 FROM DUAL

  • Oracolo

SELECT 1 FROM any_existing_table WHERE 1=0

o

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB (testato con la versione 1.8.0.10)

    Nota: ho provato a utilizzare una WHERE 1=0clausola sulla seconda query, ma non ha funzionato come valore per i DBCP di Apache Commons validationQuery, poiché la query non restituisce alcuna riga


VALUES 1 o SELECT 1 FROM SYSIBM.SYSDUMMY1

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix

Dovrebbe essere "SELEZIONA 1 DA any_existing_table DOVE 1 = 0" - altrimenti la chiamata potrebbe essere molto lenta. A proposito, sia SELECT 1 che SELECT 1 FROM DUAL funzionano anche con H2.
Thomas Mueller,

2
So che ha un paio d'anni ma potresti voler aggiungere entrambi VALUES 1e SELECT 1 FROM SYSIBM.SYSDUMMY1per Apache Derby
daiscog il

Supponendo che OP voglia una risposta Java: credo che con Java 6 questa risposta sia obsoleta. Vedi la mia risposta altrove in questa pagina.
Pietro,

Puoi aggiungere questi due alla tua risposta, DB2: "SELEZIONA la data corrente DA sysibm.sysdummy1" Informix: "seleziona il conteggio (*) da systables"
Michael

@Michael Se vuoi suggerire una modifica, la approverei. Inoltre, otterrai un paio di punti rep per questo.
Rob Hruska,

22

Se il driver è conforme a JDBC 4, non è necessaria una query dedicata per testare le connessioni. Invece, c'è Connection.isValid per testare la connessione.

JDBC 4 fa parte di Java 6 dal 2006 e il tuo driver dovrebbe supportarlo ormai!

Famosi pool di connessioni, come HikariCP, hanno ancora un parametro di configurazione per specificare una query di prova ma scoraggiano fortemente l'uso:

🔠connectionTestQuery

Se il tuo driver supporta JDBC4, ti consigliamo vivamente di non impostare questa proprietà. Questo è per database "legacy" che non supportano l'API JDBC4 Connection.isValid (). Questa è la query che verrà eseguita poco prima che ti venga data una connessione dal pool per confermare che la connessione al database è ancora attiva. Ancora una volta, prova a eseguire il pool senza questa proprietà, HikariCP registrerà un errore se il tuo driver non è conforme a JDBC4 per farti sapere. Predefinito: nessuno


9

Sfortunatamente non esiste un'istruzione SELECT che funzionerà sempre indipendentemente dal database.

La maggior parte dei database supporta:

SELECT 1

Alcuni database non lo supportano ma hanno una tabella chiamata DUAL che puoi usare quando non hai bisogno di una tabella:

SELECT 1 FROM DUAL

MySQL lo supporta anche per motivi di compatibilità, ma non tutti i database lo fanno. Una soluzione alternativa per i database che non supportano nessuno dei precedenti è creare una tabella denominata DUAL che contenga una singola riga, quindi quanto sopra funzionerà.

HSQLDB non supporta nessuno dei precedenti, quindi è possibile creare la tabella DUAL oppure utilizzare:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database

Grazie per la risposta. Ho aggiornato leggermente la mia domanda a causa della tua affermazione "non esiste alcuna istruzione SELECT che funzionerà sempre". SELECT 1 FROM DUALinoltre non funziona con HSQLDB.
Rob Hruska,

1
+1, riguarda anche la mia ricerca, in particolare per il caso HSQLDB.
Rob Hruska,

quali non supportano "seleziona 1"? Selezionare da doppio funziona solo oracolo no? Non SQL Server, o almeno MySQL
NimChimpsky

+1 Ho smesso di provare a pensare a un modo indipendente RDBMS!
Martin Smith,

2

Io uso questo:

select max(table_catalog) as x from information_schema.tables

per verificare la connessione e la capacità di eseguire query (con 1 riga come risultato) per postgreSQL, MySQL e MSSQL.


2

Io uso

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

per hsqldb 1.8.0


2

Per i test che utilizzano select count(*), dovrebbe essere più efficiente da utilizzare select count(1)perché *può causare la lettura di tutti i dati della colonna.


1

select 1 funzionerebbe in SQL Server, non sono sicuro degli altri.

Utilizzare ansi sql standard per creare una tabella e quindi eseguire una query da quella tabella.


Ansi SQL copre create table?
Martin Smith,

si lo fa. Se si utilizzano tipi di dati ansi. Sarei sorpreso se "selezionare 1" non ha funzionato però.
NimChimpsky,

1

Supponendo che l'OP voglia una risposta Java:

A partire da JDBC3 / Java 6 c'è il metodo isValid () che dovrebbe essere usato piuttosto che inventare il proprio metodo.

L'implementatore del driver deve eseguire una sorta di query sul database quando viene chiamato questo ID metodo. Tu, come semplice utente JDBC, non devi conoscere o comprendere quale sia questa query. Tutto quello che devi fare è fidarti che il creatore del driver JDBC ha svolto correttamente il suo lavoro.


2
Credo che l'OP stia parlando di una query di convalida per la configurazione del pool di connessioni di un container, non a livello di programmazione. Ad esempio, in context.xml di Tomcat, dove si imposta Risorse, è necessaria una query di convalida utilizzata da Tomcat per convalidare una connessione. Tomcat stesso dovrebbe essere modificato per sfruttare isValid (). Non è qualcosa che l'OP può controllare.
Michael

Vale anche la pena notare che "il creatore del driver JDBC ha svolto correttamente il proprio lavoro" non è realmente garantito. Ho appena scoperto che né Postgres, HSQLDB, né H2 si sono presi la briga di implementare il metodo, quindi solleverà sempre un'eccezione.
Akroy

1

Che ne dite di

SELECT user()

Lo uso prima. MySQL, H2 è OK, non conosco altri.


1

Ho appena scoperto che è difficile

SELECT 1 FROM DUAL

anche per MaxDB.


Questo non fornisce una risposta alla domanda. Una volta che hai una reputazione sufficiente , sarai in grado di commentare qualsiasi post ; fornire invece risposte che non richiedono chiarimenti da parte del richiedente . - Dalla recensione
Peter Brittain,

Non capisco, aggiunge valore alla risposta accettata, quindi dov'è il problema?
Lars Decker,

E come hai detto: poiché non posso commentare la risposta accettata, la inserisco come risposta qui. Quindi meglio non scrivere un post anche se potrebbe essere utile solo per la mancanza di reputazione?
Lars Decker,

TBH, è una chiamata stretta ... Invece di duplicare una risposta, questo avrebbe dovuto essere un commento sulla risposta originale. In caso contrario, avresti potuto apportare una modifica suggerita all'originale.
Peter Brittain,

1

Per Oracle sarà la query ad alte prestazioni

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

Questo è dal punto di vista delle prestazioni.


0

Lo uso per Firebird

select 1 from RDB$RELATION_FIELDS rows 1

0

Per MSSQL .

Questo mi ha aiutato a determinare se i server collegati erano attivi. Utilizzando una connessione Open Query e un TRY CATCH per mettere i risultati dell'errore in qualcosa di utile.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.