Truy vấn kiểm tra SQL hiệu quả hoặc truy vấn xác thực sẽ hoạt động trên tất cả (hoặc hầu hết) cơ sở dữ liệu


148

Nhiều thư viện nhóm kết nối cơ sở dữ liệu cung cấp khả năng kiểm tra các kết nối SQL của họ xem có nhàn rỗi không. Ví dụ, thư viện gộp JDBC c3p0 có một thuộc tính được gọi preferredTestQuery, được thực thi trên kết nối theo các khoảng thời gian được cấu hình. Tương tự, DBCP Apache Commons có validationQuery.

Nhiều ví dụ truy vấn tôi đã nhìn thấy là dành cho MySQL và khuyên bạn nên sử dụng SELECT 1;làm giá trị cho các truy vấn kiểm tra. Tuy nhiên, truy vấn này không hoạt động trên một số cơ sở dữ liệu (ví dụ: HSQLDB, SELECT 1dự kiến ​​có một FROMđiều khoản).

Có một truy vấn không biết cơ sở dữ liệu có hiệu quả tương đương nhưng sẽ hoạt động cho tất cả các cơ sở dữ liệu SQL không?

Biên tập:

Nếu không có (dường như là trường hợp này), ai đó có thể đề xuất một bộ truy vấn SQL sẽ hoạt động cho các nhà cung cấp cơ sở dữ liệu khác nhau không? Ý định của tôi sẽ là lập trình xác định một tuyên bố mà tôi có thể sử dụng dựa trên cấu hình nhà cung cấp cơ sở dữ liệu của mình.



1
Lưu ý: không cần thiết định cấu hình truy vấn kiểm tra nữa, xem câu trả lời của tôi bên dưới
Tim Büthe

Câu trả lời:


274

Sau một chút nghiên cứu cùng với sự giúp đỡ từ một số câu trả lời ở đây:

SELECT 1

  • H2
  • MySQL
  • Máy chủ Microsoft SQL (theo NimChimpsky )
  • PostgreSQL
  • SQLite

SELECT 1 FROM DUAL

  • Oracle

SELECT 1 FROM any_existing_table WHERE 1=0

hoặc là

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB (đã thử nghiệm với phiên bản 1.8.0.10)

    Lưu ý: Tôi đã thử sử dụng WHERE 1=0mệnh đề trên truy vấn thứ hai, nhưng nó không hoạt động như một giá trị cho DBCP của Apache Commons validationQuery, vì truy vấn không trả về bất kỳ hàng nào


VALUES 1 hoặc là SELECT 1 FROM SYSIBM.SYSDUMMY1

  • Apache Derby (thông qua daiscog )

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Thông tin

Đó phải là "CHỌN 1 TỪ any_ex hiện_table WHERE 1 = 0" - nếu không cuộc gọi có thể rất chậm. Nhân tiện, cả CHỌN 1 và CHỌN 1 TỪ DUAL cũng hoạt động với H2.
Thomas Mueller

2
Tôi biết đây là một vài năm tuổi nhưng bạn có thể muốn thêm cả hai VALUES 1SELECT 1 FROM SYSIBM.SYSDUMMY1cho Apache Derby
daiscog

Giả sử OP muốn có câu trả lời Java: Tôi tin rằng với Java 6, câu trả lời này đã lỗi thời. Xem câu trả lời của tôi ở nơi khác trên trang này.
peterh

Bạn có thể thêm hai câu này vào câu trả lời của mình, DB2: "CHỌN ngày hiện tại TỪ sysibm.sysdummy1" Informix: "select Count (*) từ systables"
Michael

@Michael Nếu bạn muốn đề xuất một chỉnh sửa, tôi sẽ phê duyệt nó. Thêm vào đó, bạn sẽ nhận được một vài điểm đại diện cho nó.
Rob Hruska

22

Nếu trình điều khiển của bạn tuân thủ JDBC 4, không cần truy vấn chuyên dụng để kiểm tra các kết nối. Thay vào đó, có Connection.isValid để kiểm tra kết nối.

JDBC 4 là một phần của Java 6 từ năm 2006 và trình điều khiển của bạn nên hỗ trợ điều này ngay bây giờ!

Các nhóm kết nối nổi tiếng, như HikariCP, vẫn có một tham số cấu hình để chỉ định truy vấn kiểm tra nhưng không khuyến khích sử dụng nó:

🔠connectionTestQuery

Nếu trình điều khiển của bạn hỗ trợ JDBC4, chúng tôi thực sự khuyên bạn không nên đặt thuộc tính này. Đây là cơ sở dữ liệu "di sản" không hỗ trợ API JDBC4 Connection.isValid (). Đây là truy vấn sẽ được thực hiện ngay trước khi kết nối được cung cấp cho bạn từ nhóm để xác thực rằng kết nối đến cơ sở dữ liệu vẫn còn tồn tại. Một lần nữa, hãy thử chạy pool mà không có thuộc tính này, HikariCP sẽ ghi lại lỗi nếu trình điều khiển của bạn không tuân thủ JDBC4 để cho bạn biết. Mặc định: không có


9

Thật không may, không có câu lệnh CHỌN sẽ luôn hoạt động bất kể cơ sở dữ liệu.

Hầu hết các cơ sở dữ liệu hỗ trợ:

SELECT 1

Một số cơ sở dữ liệu không hỗ trợ điều này nhưng có một bảng có tên DUAL mà bạn có thể sử dụng khi bạn không cần bảng:

SELECT 1 FROM DUAL

MySQL cũng hỗ trợ điều này vì lý do tương thích, nhưng không phải tất cả các cơ sở dữ liệu đều làm được. Một cách giải quyết cho các cơ sở dữ liệu không hỗ trợ một trong hai cách trên là tạo một bảng có tên DUAL chứa một hàng, sau đó ở trên sẽ hoạt động.

HSQLDB không hỗ trợ các mục trên, vì vậy bạn có thể tạo bảng DUAL hoặc sử dụng bảng khác:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database

Cảm ơn câu trả lời. Tôi đã cập nhật câu hỏi của mình một chút do câu lệnh "không có câu lệnh CHỌN nào sẽ luôn hoạt động". SELECT 1 FROM DUALcũng không hoạt động với HSQLDB.
Rob Hruska

1
+1, đây là về nơi tôi đã đến với nghiên cứu của mình, đặc biệt là đối với trường hợp HSQLDB.
Rob Hruska

Những cái nào không hỗ trợ "chọn 1"? Chọn từ kép chỉ hoạt động orory không? Không phải máy chủ sql, hoặc ít nhất là mysql
NimChimpsky

+1 Tôi đã từ bỏ việc cố gắng nghĩ về một cách độc lập RDBMS!
Martin Smith

2

Tôi sử dụng cái này:

select max(table_catalog) as x from information_schema.tables

để kiểm tra kết nối và khả năng chạy các truy vấn (với kết quả là 1 hàng) cho postgreSQL, MySQL và MSSQL.


2

tôi sử dụng

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

cho hsqldb 1.8.0


2

Đối với các thử nghiệm sử dụng select count(*), nó sẽ hiệu quả hơn để sử dụng select count(1)*có thể khiến nó đọc tất cả dữ liệu cột.


1

select 1 sẽ làm việc trong máy chủ sql, không chắc chắn về những người khác.

Sử dụng ansi sql tiêu chuẩn để tạo một bảng và sau đó truy vấn từ bảng đó.


Ansi SQL có bao gồm create tablekhông?
Martin Smith

đúng vậy Nếu bạn sử dụng các loại dữ liệu ansi. Tôi sẽ ngạc nhiên nếu "chọn 1" không hoạt động.
NimChimpsky

1

Giả sử OP muốn có câu trả lời Java:

Kể từ JDBC3 / Java 6, có phương thức isValid () nên được sử dụng thay vì phát minh ra phương thức riêng của một người.

Người triển khai trình điều khiển được yêu cầu thực hiện một số loại truy vấn đối với cơ sở dữ liệu khi id phương thức này được gọi. Bạn - với tư cách là người dùng JDBC đơn thuần - không phải biết hoặc hiểu truy vấn này là gì. Tất cả những gì bạn phải làm là tin tưởng rằng người tạo trình điều khiển JDBC đã thực hiện đúng công việc của mình.


2
Tôi tin rằng OP đang nói về một truy vấn xác thực cho cấu hình nhóm kết nối của Container, chứ không phải theo lập trình. Ví dụ: trong tệp ngữ cảnh của Tomcat, nơi bạn thiết lập Tài nguyên, phải có một trình xác thực mà Tomcat sử dụng để xác thực một kết nối. Bản thân Tomcat sẽ phải được thay đổi để tận dụng isValid (). Đó không phải là thứ mà OP có thể kiểm soát.
Michael

Cũng đáng lưu ý rằng "người tạo trình điều khiển JDBC đã thực hiện đúng công việc của mình" không thực sự được đảm bảo. Tôi chỉ thấy rằng cả Postgres, HSQLDB và H2 đều không bận tâm thực hiện phương thức này, vì vậy nó sẽ luôn đưa ra một ngoại lệ ở đó.
akroy

1

Làm thế nào về

SELECT user()

Tôi sử dụng cái này trước.MyQuery, H2 vẫn ổn, tôi không biết người khác.


1

Chỉ cần tìm ra cách khó khăn đó là

SELECT 1 FROM DUAL

cho MaxDB là tốt.


Điều này không cung cấp một câu trả lời cho câu hỏi. Một khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào ; thay vào đó, cung cấp câu trả lời không yêu cầu làm rõ từ người hỏi . - Từ đánh giá
Peter Brittain

Tôi không hiểu nó, nó làm tăng giá trị cho câu trả lời được chấp nhận, vậy vấn đề nằm ở đâu?
Lars Decker

Và như bạn đã đề cập: vì tôi không thể bình luận câu trả lời được chấp nhận, vì vậy tôi đặt nó làm câu trả lời ở đây. Vì vậy, tốt hơn không viết một bài đăng mặc dù nó có thể hữu ích chỉ vì thiếu danh tiếng?
Lars Decker

TBH, đó là một cuộc gọi gần gũi ... Thay vì sao chép một câu trả lời, đây đáng lẽ phải là một nhận xét về câu trả lời ban đầu. Không, bạn có thể chỉnh sửa đề xuất thành bản gốc.
Peter Brittain

1

Đối với Oracle, truy vấn hiệu năng cao sẽ là

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

Đây là từ một quan điểm hiệu suất.


0

Tôi sử dụng cái này cho Firebird

select 1 from RDB$RELATION_FIELDS rows 1

0

Đối với MSSQL .

Điều này giúp tôi xác định xem các máy chủ được liên kết còn sống hay không. Sử dụng kết nối Truy vấn mở và CATY TRY để đặt kết quả của lỗi thành một cái gì đó hữu ích.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.