すべて(またはほとんど)のデータベースで機能する効率的なSQLテストクエリまたは検証クエリ


148

多くのデータベース接続プールライブラリには、SQL接続のアイドル状態をテストする機能があります。たとえば、JDBCプーリングライブラリc3p0にはと呼ばれるプロパティpreferredTestQueryがあり、接続で設定された間隔で実行されます。同様に、Apache Commons DBCPにはがありvalidationQueryます。

私が見たクエリ例の 多くはMySQL 用であり、テストクエリの値として使用することをお勧めします。ただし、このクエリは一部のデータベース(たとえば、HSQLDB、句を必要とする)では機能しません。SELECT 1;SELECT 1FROM

同等に効率的ですが、すべてのSQLデータベースで機能するデータベースに依存しないクエリはありますか?

編集:

ない場合(そうであるようです)、さまざまなデータベースプロバイダーで機能する一連のSQLクエリを誰かが提案できますか?私の目的は、データベースプロバイダーの構成に基づいて、使用できるステートメントをプログラムで決定することです。


1
接続の検証については、シンプルなDB2クエリも参照してください。
dma_k

1
注:テストクエリの構成は不要になりました。以下の私の回答をご覧ください
TimBüthe16年

回答:


274

ここでいくつかの答えからの助けと一緒に少し研究した後:

SELECT 1


SELECT 1 FROM DUAL

  • オラクル

SELECT 1 FROM any_existing_table WHERE 1=0

または

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB(バージョン1.8.0.10でテスト済み)

    注:WHERE 1=02番目のクエリで句を使用しようとしましたがvalidationQuery、クエリが行を返さないため、Apache Commons DBCPの値としては機能しませんでした。


VALUES 1 または SELECT 1 FROM SYSIBM.SYSDUMMY1

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix

それは「SELECT 1 FROM any_existing_table WHERE 1 = 0」である必要があります-そうでない場合、呼び出しが非常に遅くなる可能性があります。ちなみに、SELECT 1とSELECT 1 FROM DUALはどちらもH2でも機能します。
トーマスミューラー

2
私はこれが2年前のものであることを知っていますが、両方VALUES 1SELECT 1 FROM SYSIBM.SYSDUMMY1Apache Derbyの両方を追加することもできます
daiscog

OPがJavaの回答を望んでいると仮定します。Java6では、この回答は古くなっていると思います。このページの他の場所で私の答えを参照してください。
peterh 2014年

これらの2つを回答に追加できます。DB2: "select current date FROM sysibm.sysdummy1" Informix: "select count(*)from systables"
Michael

@Michael編集を提案したい場合は、承認します。それに加えて、あなたはそれのためにいくつかの担当者ポイントを得るでしょう。
Rob Hruska、2014年

22

ドライバーがJDBC 4に準拠している場合は、接続をテストするための専用クエリは必要ありません。代わりに、Connection.isValidがあります。をテストするためのがあります。

JDBC 4は2006年のJava 6の一部であり、ドライバーはこれまでにこれをサポートするはずです!

HikariCPなどの有名な接続プールには、テストクエリを指定するための構成パラメータがまだありますが、使用しないことを強くお勧めします。

🔠connectionTestQuery

ドライバーがJDBC4をサポートしている場合、このプロパティを設定しないことを強くお勧めします。これは、JDBC4 Connection.isValid()APIをサポートしない「レガシー」データベース用です。これは、データベースへの接続がまだ有効であることを検証するために、プールから接続が与えられる直前に実行されるクエリです。繰り返しますが、このプロパティなしでプールを実行してみてください。ドライバーがJDBC4に準拠していない場合、HikariCPはエラーをログに記録して通知します。デフォルト:なし


9

残念ながら、データベースに関係なく常に機能するSELECTステートメントはありません。

ほとんどのデータベースは以下をサポートします:

SELECT 1

一部のデータベースはこれをサポートしていませんが、テーブルが不要なときに使用できるDUALというテーブルがあります。

SELECT 1 FROM DUAL

MySQLは互換性の理由からこれもサポートしていますが、すべてのデータベースがサポートしているわけではありません。上記のいずれもサポートしていないデータベースの回避策は、1つの行を含むDUALと呼ばれるテーブルを作成することです。

HSQLDBは​​上記のいずれもサポートしていないため、DUALテーブルを作成するか、以下を使用できます。

SELECT 1 FROM any_table_that_you_know_exists_in_your_database

答えてくれてありがとう。「常に機能するSELECTステートメントはありません」というステートメントのため、質問を少し更新しました。SELECT 1 FROM DUALまた、HSQLDBでは機能しません。
Rob Hruska

1
+1。これは、特にHSQLDBの場合に、私の研究にも携わってきた場所です。
Rob Hruska

「select 1」をサポートしていないものはどれですか?デュアルのみ動作するオラクルから選択しませんか?SQLサーバーではない、または少なくともmysql
NimChimpsky

+1 RDBMSに依存しない方法を考えるのをやめました!
マーティン・スミス

2

私はこれを使います:

select max(table_catalog) as x from information_schema.tables

postgreSQL、MySQL、MSSQLの接続とクエリを実行する機能(結果として1行)をチェックする。


2

私が使う

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

hsqldb 1.8.0の場合


2

を使用したテストselect count(*)では、がすべての列データを読み取るselect count(1)ため、を使用する方が効率的*です。


1

select 1 SQLサーバーで動作しますが、他についてはわかりません。

標準のansi sqlを使用してテーブルを作成し、そのテーブルからクエリを実行します。


ANSI SQLはカバーしcreate tableますか?
マーティン・スミス

はい、そうです。ANSIデータ型を使用する場合。「select 1」がうまくいかなくても驚かされます。
NimChimpsky

1

OPがJavaの回答を求めていると仮定します。

JDBC3 / Java 6以降、isValid()がありますメソッドを作成するのではなく、使用する必要があるメソッドがあります。

ドライバの実装者は、このメソッドIDが呼び出されたときに、データベースに対してなんらかのクエリを実行する必要があります。あなたは-単なるJDBCユーザーとして-このクエリが何であるかを知ったり理解したりする必要はありません。あなたがしなければならないのは、JDBCドライバの作成者が彼/彼女の仕事を適切に行ったことを信頼することです。


2
OPは、プログラムではなく、コンテナーの接続プール構成の検証クエリについて話していると思います。たとえば、リソースを設定するTomcatのcontext.xmlでは、Tomcatが接続の検証に使用するvalidationQueryを受け取ります。isValid()を利用するには、Tomcat自体を変更する必要があります。これはOPが制御できるものではありません。
Michael

「JDBCドライバーの作成者が自分の作業を適切に行っている」ことは、実際には保証されていないことにも注意してください。PostgresもHSQLDBもH2もメソッドを実装することに煩わされていないので、例外が常に発生します。
akroy 2014年

1

いかがですか

SELECT user()

私は以前これを使用しています。MySQL、H2は大丈夫です。他の人は知りません。


1

それが難しい方法を見つけた

SELECT 1 FROM DUAL

MaxDBの場合も同様です。


これは質問に対する答えを提供しません。十分な評判られると、どの投稿にもコメントできるようになります。代わりに、質問者からの説明を必要としない回答を提供してください。- レビューから
Peter Brittain

わかりません、それは受け入れられた答えに価値を加えます、それで問題はどこにありますか?
Lars Decker

そして、あなたが言ったように:私は受け入れられた答えをコメントすることができないので、私はそれを答えとしてここに置きました。評判がないからといって役立つかもしれませんが、投稿を書かない方がいいのではないでしょうか。
Lars Decker

TBH、それは危機一髪です...回答を複製するのではなく、これ元の回答に対するコメントであるべきでした。それができない場合は、オリジナルに提案された編集を行うことができます。
Peter Brittain 2016年

1

Oracleの場合、パフォーマンスの高いクエリは

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

これはパフォーマンスの観点からです。



0

以下のためのMSSQL

これは、リンクサーバーが機能しているかどうかを判断するのに役立ちました。Open Query接続とTRY CATCHを使用して、エラーの結果を有用なものにします。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.