Permintaan uji SQL yang efisien atau permintaan validasi yang akan berfungsi di semua (atau sebagian besar) database

148

Banyak perpustakaan kumpulan koneksi database menyediakan kemampuan untuk menguji koneksi SQL mereka untuk kemalasan. Sebagai contoh, perpustakaan pooling JDBC c3p0 memiliki properti bernama preferredTestQuery, yang dieksekusi pada koneksi pada interval yang dikonfigurasi. Demikian pula, Apache Commons DBCP memiliki validationQuery.

Banyak contoh kueri yang saya lihat adalah untuk MySQL dan merekomendasikan penggunaan SELECT 1;sebagai nilai untuk kueri pengujian. Namun, kueri ini tidak berfungsi pada beberapa database (misalnya HSQLDB, yang SELECT 1mengharapkan FROMklausa).

Apakah ada query database-agnostik yang setara efisien tetapi akan bekerja untuk semua database SQL?

Edit:

Jika tidak ada (yang tampaknya demikian), dapatkah seseorang menyarankan satu set query SQL yang akan bekerja untuk berbagai penyedia database? Niat saya adalah untuk secara programatik menentukan pernyataan yang dapat saya gunakan berdasarkan konfigurasi penyedia basis data saya.

Rob Hruska
sumber
1
Catatan: mengkonfigurasi kueri pengujian tidak diperlukan lagi, lihat jawaban saya di bawah ini
Tim Büthe

Jawaban:

274

Setelah sedikit riset bersama dengan bantuan dari beberapa jawaban di sini:

SELECT 1

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

SELECT 1 FROM DUAL

  • Peramal

SELECT 1 FROM any_existing_table WHERE 1=0

atau

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB (diuji dengan versi 1.8.0.10)

    Catatan: Saya mencoba menggunakan WHERE 1=0klausa pada kueri kedua, tetapi itu tidak berfungsi sebagai nilai untuk Apache Commons DBCP validationQuery, karena kueri tidak mengembalikan baris apa pun


VALUES 1 atau SELECT 1 FROM SYSIBM.SYSDUMMY1

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix
Rob Hruska
sumber
Itu harus "SELECT 1 FROM any_existing_table WHERE 1 = 0" - kalau tidak, panggilan mungkin sangat lambat. By the way, baik SELECT 1 dan SELECT 1 FROM DUAL juga bekerja dengan H2.
Thomas Mueller
2
Saya tahu ini berumur beberapa tahun tetapi Anda mungkin ingin menambahkan keduanya VALUES 1dan SELECT 1 FROM SYSIBM.SYSDUMMY1untuk Apache Derby
daiscog
Dengan asumsi OP menginginkan jawaban Java: Saya percaya bahwa dengan Java 6 jawaban ini sekarang sudah usang. Lihat jawaban saya di bagian lain halaman ini.
peterh
Anda dapat menambahkan kedua jawaban ini, DB2: "PILIH tanggal saat ini DARI sysibm.sysdummy1" Informix: "pilih count (*) dari systables"
Michael
@Michael Jika Anda ingin menyarankan hasil edit, saya akan menyetujuinya. Plus, Anda akan mendapatkan beberapa poin rep untuk itu.
Rob Hruska
22

Jika driver Anda sesuai dengan JDBC 4, tidak perlu permintaan khusus untuk menguji koneksi. Sebaliknya, ada Connection.isValid untuk menguji koneksi.

JDBC 4 adalah bagian dari Java 6 dari 2006 dan driver Anda harus mendukung ini sekarang!

Kumpulan koneksi terkenal, seperti HikariCP, masih memiliki parameter konfigurasi untuk menentukan kueri pengujian tetapi sangat tidak disarankan untuk menggunakannya:

🔠connectionTestQuery

Jika driver Anda mendukung JDBC4, kami sangat menyarankan untuk tidak menyetel properti ini. Ini untuk database "lawas" yang tidak mendukung API JDBC4 Connection.isValid (). Ini adalah kueri yang akan dieksekusi tepat sebelum koneksi diberikan kepada Anda dari kumpulan untuk memvalidasi bahwa koneksi ke database masih hidup. Sekali lagi, coba jalankan pool tanpa properti ini, HikariCP akan mencatat kesalahan jika driver Anda tidak sesuai dengan JDBC4 untuk memberi tahu Anda. Default: tidak ada

Tim Büthe
sumber
9

Sayangnya tidak ada pernyataan SELECT yang akan selalu berfungsi terlepas dari basis data.

Sebagian besar basis data mendukung:

SELECT 1

Beberapa database tidak mendukung ini tetapi memiliki tabel yang disebut DUAL yang dapat Anda gunakan saat Anda tidak membutuhkan tabel:

SELECT 1 FROM DUAL

MySQL juga mendukung ini untuk alasan kompatibilitas, tetapi tidak semua database melakukannya. Solusi untuk database yang tidak mendukung salah satu di atas adalah membuat tabel yang disebut DUAL yang berisi satu baris, maka yang di atas akan berfungsi.

HSQLDB tidak mendukung hal di atas, sehingga Anda bisa membuat tabel DUAL atau menggunakan:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database
Mark Byers
sumber
Terima kasih atas jawabannya. Saya sedikit memperbarui pertanyaan saya karena pernyataan "tidak ada pernyataan SELECT yang akan selalu berfungsi". SELECT 1 FROM DUALjuga tidak bekerja dengan HSQLDB.
Rob Hruska
1
+1, ini tentang di mana saya datang dengan penelitian saya juga, terutama untuk kasus HSQLDB.
Rob Hruska
mana yang tidak mendukung "pilih 1"? Pilih dari dua-satunya karya oracle bukan? Bukan sql server, atau mysql setidaknya
NimChimpsky
+1 Saya berhenti berusaha memikirkan cara RDBMS yang independen!
Martin Smith
2

Saya menggunakan ini:

select max(table_catalog) as x from information_schema.tables

untuk memeriksa koneksi dan kemampuan untuk menjalankan query (dengan 1 baris sebagai hasilnya) untuk postgreSQL, MySQL dan MSSQL.

Wojciechk
sumber
2

saya menggunakan

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

untuk hsqldb 1.8.0

thinkbase
sumber
2

Untuk tes yang menggunakan select count(*), harus lebih efisien untuk digunakan select count(1)karena *dapat menyebabkannya membaca semua data kolom.

Nathan Niesen
sumber
1

select 1 akan bekerja di server sql, tidak yakin tentang yang lain.

Gunakan sql ansi standar untuk membuat tabel dan kemudian kueri dari tabel itu.

NimChimpsky
sumber
Apakah ansi SQL mencakup create table?
Martin Smith
ya benar. Jika Anda menggunakan tipe data ansi. Saya akan terkejut jika "pilih 1" tidak berhasil.
NimChimpsky
1

Dengan asumsi OP menginginkan jawaban Java:

Pada JDBC3 / Java 6 ada isValid () yang harus digunakan daripada menciptakan metode sendiri.

Implementer driver diperlukan untuk mengeksekusi semacam query terhadap database ketika metode ini dipanggil. Anda - sebagai pengguna JDBC belaka - tidak harus tahu atau mengerti apa permintaan ini. Yang harus Anda lakukan adalah percaya bahwa pencipta driver JDBC telah melakukan pekerjaannya dengan benar.

peterh
sumber
2
Saya percaya OP sedang berbicara tentang permintaan validasi untuk konfigurasi kumpulan koneksi Kontainer, bukan secara terprogram. Misalnya dalam context.xml Tomcat, di mana Anda menyiapkan Sumber Daya, dibutuhkanQuery validation yang digunakan Tomcat untuk memvalidasi koneksi. Tomcat sendiri harus diubah untuk memanfaatkan isValid (). Itu bukan sesuatu yang bisa dikontrol OP.
Michael
Perlu juga dicatat bahwa "pencipta driver JDBC telah melakukan pekerjaannya dengan benar" tidak benar-benar dijamin. Saya baru saja menemukan bahwa Postgres, HSQLDB, maupun H2 tidak peduli untuk mengimplementasikan metode ini, jadi selalu ada pengecualian di sana.
akroy
1

Bagaimana tentang

SELECT user()

Saya menggunakan ini sebelumnya. MySQL, H2 tidak apa-apa, saya tidak tahu yang lain.

Wener
sumber
1

Baru tahu betapa sulitnya itu

SELECT 1 FROM DUAL

untuk MaxDB juga.

Lars Decker
sumber
Ini tidak memberikan jawaban untuk pertanyaan itu. Setelah memiliki reputasi yang cukup, Anda dapat mengomentari setiap pos ; alih-alih, berikan jawaban yang tidak memerlukan klarifikasi dari penanya . - Dari Ulasan
Peter Brittain
Saya tidak mengerti, itu menambah nilai pada jawaban yang diterima, jadi di mana masalahnya?
Lars Decker
Dan seperti yang Anda sebutkan: karena saya tidak dapat mengomentari jawaban yang diterima, maka saya menempatkannya sebagai jawaban di sini. Jadi lebih baik tidak menulis posting walaupun mungkin bermanfaat hanya karena kehilangan reputasi?
Lars Decker
TBH, ini adalah panggilan dekat ... Daripada menduplikasi jawaban, ini seharusnya komentar pada jawaban asli. Jika gagal, Anda dapat membuat edit yang disarankan ke aslinya.
Peter Brittain
1

Untuk Oracle, permintaan berkinerja tinggi adalah

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

Ini dari perspektif kinerja.

Joby Kurian
sumber
0

Saya menggunakan ini untuk Firebird

select 1 from RDB$RELATION_FIELDS rows 1
claudsan
sumber
0

Untuk MSSQL .

Ini membantu saya menentukan apakah server yang ditautkan masih hidup. Menggunakan koneksi Open Query dan TRY CATCH untuk menempatkan hasil kesalahan pada sesuatu yang bermanfaat.

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
sumber