Consulta de teste ou validação eficiente de SQL que funcionará em todos (ou na maioria) bancos de dados


148

Muitas bibliotecas de pool de conexões de banco de dados fornecem a capacidade de testar suas conexões SQL quanto à ociosidade. Por exemplo, a biblioteca de pool JDBC c3p0 possui uma propriedade chamada preferredTestQuery, que é executada na conexão em intervalos configurados. Da mesma forma, o Apache Commons DBCP possui validationQuery.

Muitos exemplos de consultas que eu vi são para o MySQL e recomendo usar SELECT 1;como valor para a consulta de teste. No entanto, essa consulta não funciona em alguns bancos de dados (por exemplo, HSQLDB, para o qual SELECT 1espera uma FROMcláusula).

Existe uma consulta independente de banco de dados que seja equivalente eficiente, mas funcionará para todos os bancos de dados SQL?

Editar:

Se não houver (o que parece ser o caso), alguém pode sugerir um conjunto de consultas SQL que funcionem para vários provedores de banco de dados? Minha intenção seria determinar programaticamente uma instrução que eu possa usar com base na configuração do meu provedor de banco de dados.



1
Nota: a configuração de uma consulta de teste não é mais necessária, veja minha resposta abaixo
Tim Büthe

Respostas:


274

Após um pouco de pesquisa, juntamente com a ajuda de algumas das respostas aqui:

SELECT 1

  • H2
  • MySQL
  • Microsoft SQL Server (de acordo com NimChimpsky )
  • PostgreSQL
  • SQLite

SELECT 1 FROM DUAL

  • Oráculo

SELECT 1 FROM any_existing_table WHERE 1=0

ou

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB (testado com a versão 1.8.0.10)

    Nota: Tentei usar uma WHERE 1=0cláusula na segunda consulta, mas ela não funcionou como um valor para os DBCP do Apache Commons validationQuery, pois a consulta não retorna nenhuma linha


VALUES 1 ou SELECT 1 FROM SYSIBM.SYSDUMMY1

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix

Isso deve ser "SELECT 1 FROM any_existing_table WHERE 1 = 0" - caso contrário, a chamada pode ser muito lenta. A propósito, SELECT 1 e SELECT 1 FROM DUAL também funcionam com H2.
Thomas Mueller

2
Eu sei que este é um par de anos, mas você pode querer adicionar ambos VALUES 1e SELECT 1 FROM SYSIBM.SYSDUMMY1para o Apache Derby
daiscog

Supondo que o OP queira uma resposta Java: Acredito que, com o Java 6, essa resposta esteja desatualizada. Veja minha resposta em outro lugar nesta página.
Peterh

Você pode adicionar esses dois à sua resposta, DB2: "SELECT date atual FROM sysibm.sysdummy1" Informix: "select count (*) from systables"
Michael

@ Michael Se você quiser sugerir uma edição, eu aprovaria. Além disso, você receberá alguns pontos de repetição por isso.
22430 Rob Hruska

22

Se o seu driver for compatível com JDBC 4, não há necessidade de uma consulta dedicada para testar as conexões. Em vez disso, há Connection.isValid para testar a conexão.

O JDBC 4 faz parte do Java 6 de 2006 e seu driver deve suportar isso agora!

Pools de conexão famosos, como o HikariCP, ainda têm um parâmetro de configuração para especificar uma consulta de teste, mas desencorajam fortemente a usá-la:

🔠connectionTestQuery

Se o seu driver suportar JDBC4, é altamente recomendável não configurar esta propriedade. Isso é para bancos de dados "legados" que não suportam a API JDBC4 Connection.isValid (). Essa é a consulta que será executada imediatamente antes de uma conexão ser fornecida a partir do pool para validar que a conexão com o banco de dados ainda está ativa. Novamente, tente executar o pool sem essa propriedade, o HikariCP registrará um erro se o driver não for compatível com JDBC4 para que você saiba. Padrão: nenhum


9

Infelizmente, não há nenhuma instrução SELECT que funcione sempre, independentemente do banco de dados.

A maioria dos bancos de dados suporta:

SELECT 1

Alguns bancos de dados não suportam isso, mas possuem uma tabela chamada DUAL que você pode usar quando não precisar de uma tabela:

SELECT 1 FROM DUAL

O MySQL também suporta isso por razões de compatibilidade, mas nem todos os bancos de dados suportam. Uma solução alternativa para bancos de dados que não suportam nenhuma das opções acima é criar uma tabela chamada DUAL que contenha uma única linha, e as opções acima funcionarão.

O HSQLDB não suporta nenhum dos itens acima, portanto você pode criar a tabela DUAL ou usar:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database

Obrigado pela resposta. Atualizei minha pergunta um pouco devido à sua declaração "não há instrução SELECT que sempre funcione". SELECT 1 FROM DUALtambém não funciona com HSQLDB.
Rob Hruska

1
+1, é sobre aqui que eu também vim com minha pesquisa, principalmente para o caso HSQLDB.
Rob Hruska

quais não suportam "selecione 1"? Selecione a partir do dual only works oracle, não é? Não SQL Server ou MySQL, pelo menos
Nim Chimpsky

Eu desisti de pensar em uma maneira independente de RDBMS!
Martin Smith

2

Eu uso este:

select max(table_catalog) as x from information_schema.tables

para verificar a conexão e a capacidade de executar consultas (com 1 linha como resultado) para postgreSQL, MySQL e MSSQL.


2

eu uso

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

para hsqldb 1.8.0


2

Para testes de uso select count(*), deve ser mais eficiente, select count(1)pois *pode fazer com que ele leia todos os dados da coluna.


1

select 1 funcionaria no servidor sql, não tenho certeza sobre os outros.

Use o ansi sql padrão para criar uma tabela e, em seguida, consulte a partir dessa tabela.


O ansi SQL cobre create table?
Martin Smith

sim. Se você usar tipos de dados ansi. Eu ficaria surpreso se "selecionar 1" não funcionasse.
NimChimpsky

1

Supondo que o OP queira uma resposta Java:

A partir do JDBC3 / Java 6, existe o método isValid () que deve ser usado em vez de inventar o próprio método.

O implementador do driver é necessário para executar algum tipo de consulta no banco de dados quando esse ID de método é chamado. Você - como um mero usuário do JDBC - não precisa saber ou entender o que é essa consulta. Tudo o que você precisa fazer é confiar que o criador do driver JDBC fez seu trabalho corretamente.


2
Acredito que o OP esteja falando de uma consulta de validação para a configuração do pool de conexões de um Contêiner, não programaticamente. Por exemplo, no context.xml do Tomcat, onde você configura Recursos, é necessária uma validationQuery que o Tomcat usa para validar uma conexão. O próprio Tomcat precisaria ser alterado para aproveitar o isValid (). Isso não é algo que o OP possa controlar.
Michael

Também é importante notar que "o criador do driver JDBC fez seu trabalho corretamente" não é realmente garantido. Acabei de descobrir que nem o Postgres, o HSQLDB nem o H2 se preocuparam em implementar o método, por isso sempre gera uma exceção lá.
akroy

1

E se

SELECT user()

Eu uso isso antes. MySQL, H2 está OK, não conheço outros.


1

Acabei de descobrir da maneira mais difícil que é

SELECT 1 FROM DUAL

para MaxDB também.


Isso não fornece uma resposta para a pergunta. Depois de ter reputação suficiente, você poderá comentar qualquer postagem ; em vez disso, forneça respostas que não exijam esclarecimentos do solicitante . - Do comentário
Peter Brittain

Não entendi, agrega valor à resposta aceita, então, onde está o problema?
Lars Decker

E como você mencionou: como não posso comentar a resposta aceita, coloquei como resposta aqui. Então é melhor não escrever um post, embora possa ser útil apenas por falta de reputação?
Lars Decker

TBH, é por um triz ... Em vez de duplicar uma resposta, isso deveria ter sido um comentário sobre a resposta original. Caso contrário, você poderia ter feito uma alteração sugerida no original.
Peter Brittain

1

Para Oracle, a consulta de alto desempenho será

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

Isso é da perspectiva de desempenho.


0

Eu uso isso para o Firebird

select 1 from RDB$RELATION_FIELDS rows 1

0

Para MSSQL .

Isso me ajudou a determinar se os servidores vinculados estavam ativos. Usando uma conexão Open Query e um TRY CATCH para colocar os resultados do erro em 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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.