แบบสอบถามการทดสอบ SQL ที่มีประสิทธิภาพหรือแบบสอบถามการตรวจสอบที่จะทำงานในฐานข้อมูล (หรือส่วนใหญ่) ทั้งหมด


148

ไลบรารีการรวมการเชื่อมต่อฐานข้อมูลจำนวนมากให้ความสามารถในการทดสอบการเชื่อมต่อ SQL ของพวกเขาเพื่อความเกียจคร้าน ตัวอย่างเช่น JDBC pooling library c3p0มีคุณสมบัติที่เรียกว่าpreferredTestQueryซึ่งถูกเรียกใช้งานบนการเชื่อมต่อตามช่วงเวลาที่กำหนดไว้ ในทำนองเดียวกัน Apache Commons DBCP validationQueryมี

แบบสอบถามตัวอย่าง จำนวนมากที่ฉันเห็นนั้นใช้สำหรับ MySQL และแนะนำให้ใช้เป็นค่าสำหรับแบบสอบถามทดสอบ อย่างไรก็ตามแบบสอบถามนี้ใช้ไม่ได้กับบางฐานข้อมูล (เช่น HSQLDB ซึ่งคาดว่าจะมีส่วนคำสั่ง)SELECT 1;SELECT 1FROM

มีแบบสอบถามแบบไม่เชื่อเรื่องพระเจ้าที่มีประสิทธิภาพเท่าเทียมกัน แต่จะใช้ได้กับฐานข้อมูล SQL ทั้งหมดหรือไม่

แก้ไข:

หากไม่มี (ซึ่งน่าจะเป็นกรณีนี้) ใครสามารถแนะนำชุดของแบบสอบถาม SQL ที่จะทำงานกับผู้ให้บริการฐานข้อมูลต่างๆได้หรือไม่ ความตั้งใจของฉันคือการกำหนดโปรแกรมที่ฉันสามารถใช้ตามการกำหนดค่าผู้ให้บริการฐานข้อมูลของฉันโดยทางโปรแกรม


1
ดูเพิ่มเติมง่าย DB2 แบบสอบถามสำหรับการตรวจสอบการเชื่อมต่อ
dma_k

1
หมายเหตุ: การกำหนดค่าแบบสอบถามทดสอบไม่จำเป็นอีกต่อไปดูคำตอบของฉันด้านล่าง
ทิมBüthe

คำตอบ:


274

หลังจากการวิจัยเล็กน้อยพร้อมความช่วยเหลือจากคำตอบบางส่วนที่นี่:

SELECT 1

  • H2
  • MySQL
  • Microsoft SQL Server (อ้างอิงจากNimChimpsky )
  • PostgreSQL
  • SQLite

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=0คำสั่งที่สอง แต่ไม่ได้ใช้เป็นค่าสำหรับ Apache Commons DBCP's validationQueryเนื่องจากแบบสอบถามไม่ส่งคืนแถวใด ๆ


VALUES 1 หรือ SELECT 1 FROM SYSIBM.SYSDUMMY1

  • Apache Derby (ผ่านdaiscog )

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix

นั่นควรจะเป็น "เลือก 1 จาก any_existing_table โดยที่ 1 = 0" - มิฉะนั้นการโทรอาจช้ามาก อย่างไรก็ตามทั้ง SELECT 1 และ SELECT 1 จาก DUAL ยังทำงานกับ H2 ได้เช่นกัน
Thomas Mueller

2
ฉันรู้ว่านี่เป็นสองสามปี แต่คุณอาจต้องการเพิ่มทั้งสองVALUES 1และSELECT 1 FROM SYSIBM.SYSDUMMY1สำหรับ Apache Derby
daiscog

สมมติว่า OP ต้องการคำตอบ Java: ฉันเชื่อว่าด้วย Java 6 คำตอบนี้ล้าสมัยแล้ว ดูคำตอบของฉันที่อื่นในหน้านี้
เตอร์

คุณสามารถเพิ่มสองสิ่งนี้ในคำตอบของคุณ DB2: "เลือกวันที่ปัจจุบันจาก sysibm.sysdummy1" Informix: "select count (*) จาก systables"
Michael

@Michael หากคุณต้องการแนะนำการแก้ไขฉันจะอนุมัติ นอกจากนี้คุณจะได้รับคะแนนตัวแทนสองเท่า
Rob Hruska

22

หากไดรเวอร์ของคุณเป็นไปตามมาตรฐาน JDBC 4 ไม่จำเป็นต้องใช้แบบสอบถามเฉพาะเพื่อทดสอบการเชื่อมต่อ แต่มีConnection.isValidเพื่อทดสอบการเชื่อมต่อแทน

JDBC 4 เป็นส่วนหนึ่งของ Java 6 ตั้งแต่ปี 2549 และคุณควรให้การสนับสนุนในตอนนี้

พูลการเชื่อมต่อที่มีชื่อเสียงเช่น HikariCP ยังมีพารามิเตอร์กำหนดค่าสำหรับการระบุแบบสอบถามทดสอบ แต่ไม่แนะนำให้ใช้อย่างยิ่ง:

🔠connectionTestQuery

หากไดรเวอร์ของคุณรองรับ JDBC4 เราขอแนะนำอย่างยิ่งว่าอย่าตั้งค่าคุณสมบัตินี้ สิ่งนี้มีไว้สำหรับฐานข้อมูล "ดั้งเดิม" ที่ไม่สนับสนุน JDBC4 Connection.isValid () API นี่คือแบบสอบถามที่จะถูกดำเนินการก่อนที่จะมีการเชื่อมต่อกับคุณจากกลุ่มเพื่อตรวจสอบว่าการเชื่อมต่อกับฐานข้อมูลยังคงมีอยู่ ลองเรียกใช้พูลโดยไม่มีคุณสมบัตินี้ HikariCP จะบันทึกข้อผิดพลาดหากไดรเวอร์ของคุณไม่สอดคล้องกับ JDBC4 เพื่อแจ้งให้คุณทราบ เริ่มต้น: ไม่มี


9

น่าเสียดายที่ไม่มีคำสั่ง SELECT ที่ใช้งานได้ทุกเมื่อโดยไม่คำนึงถึงฐานข้อมูล

ฐานข้อมูลส่วนใหญ่รองรับ:

SELECT 1

ฐานข้อมูลบางตัวไม่รองรับสิ่งนี้ แต่มีตารางชื่อ DUAL ที่คุณสามารถใช้เมื่อคุณไม่ต้องการตาราง:

SELECT 1 FROM DUAL

MySQL รองรับสิ่งนี้ด้วยเหตุผลด้านความเข้ากันได้ แต่ไม่ใช่ทุกฐานข้อมูล วิธีหลีกเลี่ยงปัญหาสำหรับฐานข้อมูลที่ไม่สนับสนุนข้อใดข้อหนึ่งข้างต้นคือการสร้างตารางชื่อ 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

อันไหนไม่รองรับ "เลือก 1" เลือกจาก dual เท่านั้น oracle ทำงานไม่ได้หรือไม่ ไม่ใช่เซิร์ฟเวอร์ sql หรืออย่างน้อย mysql
NimChimpsky

+1 ฉันเลิกพยายามคิดอย่างอิสระ RDBMS!
Martin Smith

2

ฉันใช้อันนี้:

select max(table_catalog) as x from information_schema.tables

เพื่อตรวจสอบการเชื่อมต่อและความสามารถในการเรียกใช้คิวรี (ด้วยผล 1 แถว) สำหรับ postgreSQL, MySQL และ MSSQL



2

สำหรับการทดสอบที่ใช้select count(*)ควรมีประสิทธิภาพมากกว่าในการใช้select count(1)เนื่องจาก*อาจทำให้อ่านข้อมูลคอลัมน์ทั้งหมดได้


1

select 1 จะทำงานในเซิร์ฟเวอร์ sql ไม่แน่ใจเกี่ยวกับคนอื่น

ใช้ ansi sql มาตรฐานเพื่อสร้างตารางจากนั้นสอบถามจากตารางนั้น


ansi SQL ครอบคลุมcreate tableหรือไม่
Martin Smith

ใช่แล้ว. ถ้าคุณใช้ชนิดข้อมูล ansi ฉันจะแปลกใจถ้า "เลือก 1" ไม่ทำงาน
NimChimpsky

1

สมมติว่า OP ต้องการคำตอบ Java:

ในฐานะของ JDBC3 / Java 6 มีisValid ()ซึ่งควรใช้แทนที่จะประดิษฐ์วิธีของตัวเอง

implementer ของไดร์เวอร์จำเป็นต้องเรียกใช้งานเคียวรีบางประเภทเทียบกับฐานข้อมูลเมื่อเมธอด id นี้เรียกว่า คุณ - ในฐานะผู้ใช้ JDBC - ไม่จำเป็นต้องรู้หรือเข้าใจว่าแบบสอบถามนี้คืออะไร สิ่งที่คุณต้องทำคือการวางใจว่าผู้สร้างไดรเวอร์ JDBC ทำงานได้อย่างถูกต้อง


2
ฉันเชื่อว่า OP กำลังพูดถึงแบบสอบถามการตรวจสอบความถูกต้องสำหรับการกำหนดค่าพูลการเชื่อมต่อของ Container ไม่ใช่การเขียนโปรแกรม ตัวอย่างเช่นในบริบทของ Tomcat ที่คุณตั้งค่าทรัพยากรจะใช้ validationQuery ที่ Tomcat ใช้เพื่อตรวจสอบการเชื่อมต่อ Tomcat จะต้องเปลี่ยนแปลงเพื่อใช้ประโยชน์จาก isValid () นั่นไม่ใช่สิ่งที่ OP สามารถควบคุมได้
Michael

นอกจากนี้ยังเป็นที่น่าสังเกตว่า "ผู้สร้างไดรเวอร์ JDBC ทำงานอย่างถูกต้อง" ไม่รับประกัน ฉันเพิ่งพบว่าทั้ง Postgres, HSQLDB และ H2 ไม่ใส่ใจที่จะใช้วิธีนี้ดังนั้นมันจะยกข้อยกเว้นที่นั่นเสมอ
akroy

1

เกี่ยวกับ

SELECT user()

ฉันเคยใช้มันมาก่อน MySQL, H2 ก็โอเคฉันไม่รู้จักคนอื่น


1

เพิ่งค้นพบวิธีที่ยากที่มันเป็น

SELECT 1 FROM DUAL

สำหรับ MaxDB เช่นกัน


สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม เมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด ๆ ; แทนที่จะให้คำตอบที่ไม่จำเป็นต้องชี้แจงจากผู้ถาม - จากรีวิว
Peter Brittain

ฉันไม่เข้าใจมันเพิ่มคุณค่าให้กับคำตอบที่ยอมรับแล้วปัญหาอยู่ที่ไหน
Lars Decker

และอย่างที่คุณพูดถึง: ในขณะที่ฉันไม่สามารถแสดงความคิดเห็นคำตอบที่ยอมรับได้ฉันจึงใส่คำตอบไว้ที่นี่ ดังนั้นดีกว่าไม่เขียนโพสต์ถึงแม้ว่ามันอาจจะเป็นประโยชน์เพียงเพราะขาดชื่อเสียง?
Lars Decker

TBH มันเป็นการโทรที่ใกล้ชิด ... แทนที่จะทำซ้ำคำตอบนี่น่าจะเป็นความเห็นของคำตอบเดิม หากไม่สามารถทำเช่นนั้นคุณอาจทำการแก้ไขที่แนะนำให้กับต้นฉบับ
Peter Brittain

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.