Tüm (veya çoğu) veritabanında çalışacak verimli SQL test sorgusu veya doğrulama sorgusu


152

Birçok veritabanı bağlantı havuzu kitaplığı, SQL bağlantılarını boşta kalma açısından test etme yeteneği sağlar. Örneğin, JDBC havuzlama kitaplığı c3p0 , preferredTestQuerybağlantıda yapılandırılmış aralıklarla çalıştırılan adında bir özelliğe sahiptir . Benzer şekilde, Apache Commons DBCP'de validationQuery.

Gördüğüm birçok örnek sorgu MySQL SELECT 1;içindir ve test sorgusu için değer olarak kullanılmasını önerir . Ancak, bu sorgu bazı veritabanlarında çalışmaz (örn. HSQLDB, kendisi için SELECT 1bir FROMcümle beklemektedir ).

Eşit derecede verimli olan ancak tüm SQL veritabanları için çalışacak bir veritabanından bağımsız sorgu var mı?

Düzenle:

Eğer yoksa (öyle görünüyor ki), birileri çeşitli veritabanı sağlayıcıları için çalışacak bir dizi SQL sorgusu önerebilir mi? Niyetim, veritabanı sağlayıcısı yapılandırmamı temel alarak kullanabileceğim bir ifadeyi programlı olarak belirlemek olacaktır.



1
Not: Bir test sorgusu yapılandırarak, artık gerekli görmedim benim cevap aşağıda
Tim Büthe

Yanıtlar:


281

Buradaki bazı cevapların yardımıyla biraz araştırma yaptıktan sonra:

SELECT 1

  • H2
  • MySQL
  • Microsoft SQL Sunucusu ( NimChimpsky'ye göre )
  • PostgreSQL
  • SQLite

SELECT 1 FROM DUAL

  • Oracle

SELECT 1 FROM any_existing_table WHERE 1=0

veya

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

veya

CALL NOW()

  • HSQLDB (1.8.0.10 sürümüyle test edilmiştir)

    Not: WHERE 1=0İkinci sorguda bir yan tümce kullanmayı denedim , ancak validationQuerysorgu herhangi bir satır döndürmediğinden Apache Commons DBCP'ler için bir değer olarak çalışmadı


VALUES 1 veya SELECT 1 FROM SYSIBM.SYSDUMMY1

  • Apache Derby ( daiscog aracılığıyla )

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix

Bu "herhangi bir_ varolan_tablondan 1 = 0 SEÇİN" olmalıdır - aksi takdirde çağrı çok yavaş olabilir. Bu arada, hem SEÇ 1 hem de ÇİFTTEN SEÇ 1 de H2 ile çalışır.
Thomas Mueller

2
Bu eski birkaç yıl olduğunu biliyorum ama her ikisi eklemek isteyebilirsiniz VALUES 1ve SELECT 1 FROM SYSIBM.SYSDUMMY1Apache Derby için
daiscog

OP'nin bir Java cevabı istediğini varsayarsak: Java 6 ile bu cevabın artık modası geçmiş olduğuna inanıyorum. Cevabımı bu sayfada başka bir yerde görebilirsiniz.
peterh

Bu ikisini yanıtınıza ekleyebilirsiniz, DB2: "sysibm.sysdummy1'den geçerli tarihi SEÇİN" Informix: "systables'dan sayımı (*) seçin"
Michael

@Michael Bir düzenleme önermek isterseniz, onaylarım. Artı, bunun için birkaç tekrar puanı alacaksınız.
Rob Hruska

23

Sürücünüz JDBC 4 uyumluysa, bağlantıları test etmek için özel bir sorguya gerek yoktur. Bunun yerine, bağlantıyı test etmek için Connection.isValid vardır .

JDBC 4, 2006'dan itibaren Java 6'nın bir parçasıdır ve sürücünüz bunu şimdiye kadar desteklemelidir!

HikariCP gibi ünlü bağlantı havuzları, bir test sorgusu belirtmek için hala bir yapılandırma parametresine sahiptir, ancak bunu kullanmaktan kesinlikle kaçınılır:

🔠connectionTestQuery

Sürücünüz JDBC4'ü destekliyorsa, bu özelliği ayarlamamanızı kesinlikle öneririz. Bu, JDBC4 Connection.isValid () API'yi desteklemeyen "eski" veritabanları içindir. Bu, veritabanına bağlantının hala canlı olduğunu doğrulamak için havuzdan size bir bağlantı verilmeden hemen önce yürütülecek sorgudur. Yine, havuzu bu özellik olmadan çalıştırmayı deneyin, HikariCP, sürücünüz size bildirmek için JDBC4 uyumlu değilse bir hata günlüğe kaydedecektir. Varsayılan: yok


9

Ne yazık ki, veritabanından bağımsız olarak her zaman çalışacak bir SELECT ifadesi yoktur.

Çoğu veritabanı şunları destekler:

SELECT 1

Bazı veritabanları bunu desteklemez ancak bir tabloya ihtiyacınız olmadığında kullanabileceğiniz DUAL adlı bir tabloya sahiptir:

SELECT 1 FROM DUAL

MySQL ayrıca uyumluluk nedeniyle bunu destekler, ancak tüm veritabanları desteklemez. Yukarıdakilerden hiçbirini desteklemeyen veritabanları için bir geçici çözüm, tek bir satır içeren DUAL adlı bir tablo oluşturmaktır, bu durumda yukarıdakiler çalışacaktır.

HSQLDB yukarıdakilerin hiçbirini desteklemediğinden, DUAL tabloyu oluşturabilir veya başka bir şekilde kullanabilirsiniz:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database

Cevap için teşekkürler. "Her zaman işe yarayacak bir SELECT ifadesi yoktur" ifadeniz nedeniyle sorumu biraz güncelledim. SELECT 1 FROM DUALayrıca HSQLDB ile de çalışmaz.
Rob Hruska

1
+1, burası özellikle HSQLDB vakası için araştırmamla birlikte geldiğim yerle ilgili.
Rob Hruska

hangileri "1'i seç" i desteklemiyor? İkili seçim sadece oracle çalışır değil mi? Değil sql server veya en azından mysql
NimChimpsky

+1 RDBMS'den bağımsız bir yol düşünmekten vazgeçtim!
Martin Smith

2

Bunu kullanıyorum:

select max(table_catalog) as x from information_schema.tables

postgreSQL, MySQL ve MSSQL için bağlantıyı ve sorgu çalıştırma yeteneğini (sonuç olarak 1 satır ile) kontrol etmek için.


2

kullanırım

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

hsqldb 1.8.0 için


2

Kullanarak testler için select count(*), kullanımda daha etkili olması gerektiğini select count(1), çünkü *tüm sütun verilerini okumak için neden olabilir.


1

select 1 diğerleri hakkında emin değil, sql sunucusunda çalışır.

Bir tablo oluşturmak için standart ansi sql kullanın ve ardından bu tablodan sorgulama yapın.


Ansi SQL kapsıyor create tablemu?
Martin Smith

Evet öyle. Ansi veri türlerini kullanıyorsanız. Yine de "1'i seçin" işe yaramazsa şaşırırdım.
NimChimpsky

1

OP'nin bir Java yanıtı istediğini varsayarsak:

JDBC3 / Java 6'dan itibaren, kişinin kendi yöntemini icat etmek yerine kullanılması gereken isValid () yöntemi vardır.

Sürücünün uygulayıcısının, bu yöntem kimliği çağrıldığında veritabanına karşı bir tür sorgu yürütmesi gerekir. Yalnızca bir JDBC kullanıcısı olarak, bu sorgunun ne olduğunu bilmek veya anlamak zorunda değilsiniz. Tek yapmanız gereken, JDBC sürücüsünün yaratıcısının işini düzgün bir şekilde yaptığına güvenmektir.


2
Operatörün, programlı olarak değil, bir Konteyner bağlantı havuzu yapılandırması için bir doğrulama sorgusundan bahsettiğine inanıyorum. Örneğin, Resources'ı kurduğunuz Tomcat'in context.xml'sinde, Tomcat'in bir bağlantıyı doğrulamak için kullandığı bir validationQuery alır. İsValid () işlevinden yararlanmak için Tomcat'in kendisinin değiştirilmesi gerekir. Bu, OP'nin kontrol edebileceği bir şey değil.
Michael

Ayrıca şunu da belirtmek gerekir ki, "JDBC sürücüsünün yaratıcısı işini düzgün bir şekilde yapmıştır" gerçekten garanti değildir. Ne Postgres, HSQLDB ne de H2'nin yöntemi uygulamaktan rahatsız olmadıklarını buldum, bu yüzden orada her zaman bir istisna oluşturacaktır.
akroy

1

Ne dersin

SELECT user()

Bunu daha önce kullanmıştım. MySQL, H2 tamam, başkalarını tanımıyorum.


1

Sadece zor yoldan öğrendim

SELECT 1 FROM DUAL

MaxDB için de.


Bu soruya bir cevap vermiyor. Yeterli itibara sahip olduğunuzda , herhangi bir gönderi hakkında yorum yapabileceksiniz ; bunun yerine soruyu soranın açıklamasını gerektirmeyen yanıtlar verin . - Yorumdan
Peter Brittain

Anlamıyorum, kabul edilen cevaba değer katıyor, peki sorun nerede?
Lars Decker

Ve belirttiğiniz gibi: kabul edilen cevabı yorumlayamayacağım için, bu yüzden buraya cevap olarak koyuyorum. Öyleyse, sadece itibar eksikliğinden dolayı yardımcı olabilmesine rağmen bir gönderi yazmamak daha iyidir?
Lars Decker

TBH, bu yakın bir çağrı ... Bir cevabı kopyalamaktansa, bu orijinal cevaba bir yorum olmalıydı . Aksi takdirde, orijinal için önerilen bir düzenleme yapmış olabilirsiniz.
Peter Brittain

1

Oracle için yüksek performanslı sorgu,

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

Bu performans perspektifinden.


0

Bunu Firebird için kullanıyorum

select 1 from RDB$RELATION_FIELDS rows 1

0

İçin MSSQL .

Bu, bağlantılı sunucuların canlı olup olmadığını belirlememe yardımcı oldu. Hatanın sonuçlarını faydalı bir şeye koymak için bir Açık Sorgu bağlantısı ve bir DENEME YAKALAMA kullanma.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.