ในการรักษาผู้ใช้แอปพลิเคชันหรือเว็บไซต์ใด ๆ ต้องทำงานได้อย่างรวดเร็ว สำหรับสภาพแวดล้อมที่สำคัญของภารกิจความล่าช้าในการรับข้อมูลสองสามมิลลิวินาทีอาจสร้างปัญหาใหญ่ได้ เนื่องจากขนาดฐานข้อมูลเติบโตขึ้นทุกวันเราจึงจำเป็นต้องดึงข้อมูลให้เร็วที่สุดและเขียนข้อมูลกลับลงในฐานข้อมูลให้เร็วที่สุด เพื่อให้แน่ใจว่าการดำเนินการทั้งหมดดำเนินไปอย่างราบรื่นเราต้องปรับแต่งเซิร์ฟเวอร์ฐานข้อมูลของเราเพื่อประสิทธิภาพ
ในบทความนี้ฉันจะอธิบายขั้นตอนทีละขั้นตอนสำหรับการปรับแต่งประสิทธิภาพขั้นพื้นฐานบนเซิร์ฟเวอร์ฐานข้อมูลอันดับต้น ๆ ในตลาด: Microsoft เซิร์ฟเวอร์ SQL (SQL Server สั้น ๆ )
เช่นเดียวกับซอฟต์แวร์อื่น ๆ เราต้องเข้าใจว่า SQL Server เป็นโปรแกรมคอมพิวเตอร์ที่ซับซ้อน หากเรามีปัญหาเราจำเป็นต้องค้นหาว่าเหตุใดจึงไม่ทำงานตามที่เราคาดหวัง
จาก SQL Server เราต้องดึงและพุชข้อมูลให้เร็วและแม่นยำที่สุด หากมีปัญหาสาเหตุพื้นฐานสองสามประการและสองสิ่งแรกที่ต้องตรวจสอบ ได้แก่ :
แม้ว่า SQL Server จะเป็นซอฟต์แวร์ที่เป็นกรรมสิทธิ์ แต่ Microsoft ก็มีวิธีมากมายในการทำความเข้าใจและใช้งานอย่างมีประสิทธิภาพ
หากฮาร์ดแวร์ตกลงและการติดตั้งเสร็จสิ้นอย่างถูกต้อง แต่ SQL Server ยังคงทำงานช้าอันดับแรกเราต้องหาว่ามีข้อผิดพลาดเกี่ยวกับซอฟต์แวร์หรือไม่ ในการตรวจสอบสิ่งที่เกิดขึ้นเราต้องสังเกตประสิทธิภาพของเธรดต่างๆ ทำได้โดยการคำนวณสถิติการรอของเธรดที่แตกต่างกัน เซิร์ฟเวอร์ SQL ใช้เธรดสำหรับคำขอของผู้ใช้ทุกคนและเธรดก็ไม่มีอะไรนอกจากโปรแกรมอื่นในโปรแกรมที่ซับซ้อนของเราที่เรียกว่า SQL Server สิ่งสำคัญคือต้องทราบว่าเธรดนี้ไม่ใช่เธรดระบบปฏิบัติการที่ติดตั้งเซิร์ฟเวอร์ SQL มันเกี่ยวข้องกับเธรด SQLOS ซึ่งเป็นระบบปฏิบัติการหลอกสำหรับ SQL Server
สามารถคำนวณสถิติการรอโดยใช้ sys.dm_os_wait_stats
Dynamic Management View (DMV) ซึ่งให้ข้อมูลเพิ่มเติมเกี่ยวกับสถานะปัจจุบัน มีสคริปต์มากมายออนไลน์เพื่อค้นหามุมมองนี้ แต่สิ่งที่ฉันชอบคือ สคริปต์ของ Paul Randal เพราะเข้าใจง่ายและมีพารามิเตอร์ที่สำคัญทั้งหมดในการสังเกตสถิติการรอ:
WITH [Waits] AS (SELECT [wait_type], [wait_time_ms] / 1000.0 AS [WaitS], ([wait_time_ms] - [signal_wait_time_ms]) / 1000.0 AS [ResourceS], [signal_wait_time_ms] / 1000.0 AS [SignalS], [waiting_tasks_count] AS [WaitCount], 100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage], ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum] FROM sys.dm_os_wait_stats WHERE [wait_type] NOT IN ( N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP', N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE', N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE', N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_WORKER_QUEUE', N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE', N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX', N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT', N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE', N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE', N'ONDEMAND_TASK_QUEUE', N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH', N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP', N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY', N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK', N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP', N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'SQLTRACE_WAIT_ENTRIES', N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT', N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'XE_DISPATCHER_JOIN', N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT') AND [waiting_tasks_count] > 0 ) SELECT MAX ([W1].[wait_type]) AS [WaitType], CAST (MAX ([W1].[WaitS]) AS DECIMAL (16,2)) AS [Wait_S], CAST (MAX ([W1].[ResourceS]) AS DECIMAL (16,2)) AS [Resource_S], CAST (MAX ([W1].[SignalS]) AS DECIMAL (16,2)) AS [Signal_S], MAX ([W1].[WaitCount]) AS [WaitCount], CAST (MAX ([W1].[Percentage]) AS DECIMAL (5,2)) AS [Percentage], CAST ((MAX ([W1].[WaitS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgWait_S], CAST ((MAX ([W1].[ResourceS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgRes_S], CAST ((MAX ([W1].[SignalS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgSig_S] FROM [Waits] AS [W1] INNER JOIN [Waits] AS [W2] ON [W2].[RowNum] <= [W1].[RowNum] GROUP BY [W1].[RowNum] HAVING SUM ([W2].[Percentage]) - MAX ([W1].[Percentage]) < 95; -- percentage threshold GO
เมื่อเราเรียกใช้สคริปต์นี้เราต้องให้ความสำคัญกับแถวบนสุดของผลลัพธ์เนื่องจากถูกตั้งค่าก่อนและแสดงถึงประเภทการรอสูงสุด
เราจำเป็นต้องเข้าใจประเภทการรอเพื่อให้สามารถตัดสินใจได้อย่างถูกต้อง หากต้องการเรียนรู้เกี่ยวกับการรอประเภทต่างๆเราสามารถไปที่ยอดเยี่ยม เอกสารของ Microsoft .
มาดูตัวอย่างที่เรามี PAGEIOLATCH_XX
มากเกินไป ซึ่งหมายความว่าเธรดกำลังรอให้เพจข้อมูลอ่านจากดิสก์ลงในบัฟเฟอร์ซึ่งไม่มีอะไรเลยนอกจากบล็อกหน่วยความจำ เราต้องแน่ใจว่าเราเข้าใจสิ่งที่เกิดขึ้น นี่ไม่จำเป็นต้องหมายถึงระบบย่อย I / O ที่ไม่ดีหรือหน่วยความจำไม่เพียงพอและการเพิ่มระบบย่อย I / O และหน่วยความจำจะช่วยแก้ปัญหาได้ แต่เพียงชั่วคราว ในการค้นหาวิธีแก้ปัญหาถาวรเราต้องดูว่าเหตุใดจึงมีการอ่านข้อมูลจำนวนมากจากดิสก์: คำสั่ง SQL ประเภทใดที่ทำให้เกิดสิ่งนี้ เรากำลังอ่านข้อมูลมากเกินไปแทนที่จะอ่านข้อมูลน้อยลงโดยใช้ตัวกรองเช่น where
อนุประโยค? มีการอ่านข้อมูลมากเกินไปเนื่องจากการสแกนตารางหรือการสแกนดัชนี? เราสามารถแปลงเป็นดัชนีค้นหาโดยใช้หรือปรับเปลี่ยนดัชนีที่มีอยู่? เรากำลังเขียนแบบสอบถาม SQL ที่ SQL Optimizer เข้าใจผิด (โปรแกรมอื่นในโปรแกรมเซิร์ฟเวอร์ SQL ของเรา) หรือไม่
เราต้องคิดจากมุมที่แตกต่างกันและใช้กรณีทดสอบที่แตกต่างกันเพื่อหาแนวทางแก้ไข การรอแต่ละประเภทข้างต้นต้องการวิธีแก้ปัญหาที่แตกต่างกัน ผู้ดูแลระบบฐานข้อมูลจำเป็นต้องค้นคว้าข้อมูลอย่างละเอียดก่อนดำเนินการใด ๆ แต่ส่วนใหญ่แล้วการค้นหาคำค้นหา T-SQL ที่มีปัญหาและปรับแต่งจะช่วยแก้ปัญหาได้ 60 ถึง 70 เปอร์เซ็นต์
ดังที่กล่าวไว้ข้างต้นสิ่งแรกที่เราทำได้คือค้นหาคำค้นหาที่เป็นปัญหา รหัส T-SQL ต่อไปนี้จะค้นหา 20 คำค้นหาที่มีประสิทธิภาพแย่ที่สุด:
SELECT TOP 20 total_worker_time/execution_count AS Avg_CPU_Time ,Execution_count ,total_elapsed_time/execution_count as AVG_Run_Time ,total_elapsed_time ,(SELECT SUBSTRING(text,statement_start_offset/2+1,statement_end_offset ) FROM sys.dm_exec_sql_text(sql_handle) ) AS Query_Text FROM sys.dm_exec_query_stats ORDER BY Avg_CPU_Time DESC
เราต้องระมัดระวังกับผลลัพธ์ แม้ว่าแบบสอบถามจะมีเวลารันเฉลี่ยสูงสุด แต่หากรันเพียงครั้งเดียวผลรวมบนเซิร์ฟเวอร์ก็ต่ำเมื่อเทียบกับคิวรีที่มีเวลาทำงานเฉลี่ยปานกลางและทำงานหลายครั้งในหนึ่งวัน
การปรับแต่งแบบสอบถาม T-SQL เป็นแนวคิดที่สำคัญ สิ่งพื้นฐานที่ต้องเข้าใจคือเราสามารถเขียนแบบสอบถาม T-SQL และใช้ดัชนีได้ดีเพียงใดเพื่อให้เครื่องมือเพิ่มประสิทธิภาพ SQL สามารถค้นหาแผนการที่เหมาะสมที่สุดเพื่อทำสิ่งที่เราต้องการให้ทำ ด้วย SQL Server รุ่นใหม่ทุกครั้งเราได้รับเครื่องมือเพิ่มประสิทธิภาพที่ซับซ้อนยิ่งขึ้นซึ่งจะครอบคลุมข้อผิดพลาดของเราในการเขียนแบบสอบถาม SQL ที่ไม่ได้รับการปรับให้เหมาะสมและจะแก้ไขข้อบกพร่องใด ๆ ที่เกี่ยวข้องกับเครื่องมือเพิ่มประสิทธิภาพก่อนหน้านี้ แต่ไม่ว่าเครื่องมือเพิ่มประสิทธิภาพจะชาญฉลาดเพียงใดหากเราไม่สามารถบอกสิ่งที่ต้องการได้ (โดยการเขียนคำค้นหา T-SQL ที่เหมาะสม) เครื่องมือเพิ่มประสิทธิภาพ SQL จะไม่สามารถทำงานได้
SQL Server ใช้การค้นหาขั้นสูงและ อัลกอริทึมการเรียงลำดับ . หากเราเก่งในการค้นหาและจัดเรียงอัลกอริทึมส่วนใหญ่แล้วเราสามารถเดาได้ว่าเหตุใด SQL Server จึงดำเนินการบางอย่าง หนังสือที่ดีที่สุดสำหรับการเรียนรู้เพิ่มเติมและทำความเข้าใจอัลกอริทึมดังกล่าวคือ ศิลปะการเขียนโปรแกรมคอมพิวเตอร์ โดย Donald Knuth .
เมื่อเราตรวจสอบคำค้นหาที่จำเป็นต้องได้รับการปรับแต่งอย่างละเอียดเราจำเป็นต้องใช้แผนการดำเนินการของแบบสอบถามเหล่านั้นเพื่อที่เราจะได้ทราบว่าเซิร์ฟเวอร์ SQL ตีความคำเหล่านั้นอย่างไร
ฉันไม่สามารถครอบคลุมทุกแง่มุมของแผนการดำเนินการที่นี่ แต่ในระดับพื้นฐานฉันสามารถอธิบายสิ่งที่เราต้องพิจารณาได้
แม้ว่าเราจะใช้ดัชนีที่เหมาะสมบนตารางและเขียนโค้ด T-SQL ที่ดีหากไม่นำแผนการดำเนินการมาใช้ซ้ำเราก็จะมีปัญหาด้านประสิทธิภาพ หลังจากปรับแต่งแบบสอบถามอย่างละเอียดแล้วเราจำเป็นต้องตรวจสอบให้แน่ใจว่าอาจมีการใช้แผนการดำเนินการอีกครั้งเมื่อจำเป็น เวลาส่วนใหญ่ของ CPU จะใช้ไปกับการคำนวณแผนการดำเนินการที่สามารถกำจัดได้หากเราใช้แผนซ้ำ
เราสามารถใช้แบบสอบถามด้านล่างเพื่อดูว่ามีการใช้แผนการดำเนินการซ้ำกี่ครั้งโดยที่ usecounts
แสดงจำนวนครั้งที่มีการใช้แผนซ้ำ:
SELECT [ecp].[refcounts] , [ecp].[usecounts] , [ecp].[objtype] , DB_NAME([est].[dbid]) AS [db_name] , [est].[objectid] , [est].[text] as [query_ext] , [eqp].[query_plan] FROM sys.dm_exec_cached_plans ecp CROSS APPLY sys.dm_exec_sql_text ( ecp.plan_handle ) est CROSS APPLY sys.dm_exec_query_plan ( ecp.plan_handle ) eqp
วิธีที่ดีที่สุดในการนำแผนการดำเนินการกลับมาใช้คือการใช้โพรซีเดอร์ที่จัดเก็บแบบกำหนดพารามิเตอร์ เมื่อเราไม่อยู่ในตำแหน่งที่จะใช้โพรซีเดอร์ที่จัดเก็บไว้เราสามารถใช้ sp_executesql
ซึ่งสามารถใช้แทนคำสั่ง T-SQL ได้เมื่อการเปลี่ยนแปลงเพียงคำสั่ง SQL เป็นค่าพารามิเตอร์ SQL Server มักจะใช้แผนการดำเนินการที่สร้างขึ้นในการดำเนินการครั้งแรก
เช่นเดียวกับโปรแกรมคอมพิวเตอร์ที่ซับซ้อนไม่มีวิธีแก้ปัญหาที่ตายตัว บางครั้งจะดีกว่าที่จะรวบรวมแผนอีกครั้ง
ลองตรวจสอบสองตัวอย่างการสืบค้นดังต่อไปนี้:
select name from table where name = 'sri';
select name from table where name = 'pal';
สมมติว่าเรามีดัชนีที่ไม่ใช่คลัสเตอร์บน name
คอลัมน์และครึ่งหนึ่งของตารางมีค่า sri
และไม่กี่แถวมี pal
ใน name
คอลัมน์. สำหรับแบบสอบถามแรก SQL Server จะใช้การสแกนตารางเนื่องจากครึ่งหนึ่งของตารางมีค่าเหมือนกัน แต่สำหรับแบบสอบถามที่สองควรใช้การสแกนดัชนีเนื่องจากมีเพียงไม่กี่แถวเท่านั้นที่มี pal
มูลค่า.
แม้ว่าข้อความค้นหาจะคล้ายกัน แต่แผนการดำเนินการเดียวกันอาจไม่ใช่ทางออกที่ดี ส่วนใหญ่แล้วจะเป็นกรณีที่แตกต่างกันดังนั้นเราต้องวิเคราะห์ทุกอย่างอย่างรอบคอบก่อนตัดสินใจ หากเราไม่ต้องการใช้แผนการดำเนินการซ้ำเราสามารถใช้ตัวเลือก 'คอมไพล์ใหม่' ในโพรซีเดอร์ที่จัดเก็บไว้ได้ตลอดเวลา
โปรดทราบว่าแม้จะใช้กระบวนงานที่จัดเก็บไว้หรือ sp_executesql
แล้วก็ยังมีบางครั้งที่จะไม่นำแผนการดำเนินการกลับมาใช้อีก พวกเขาคือ:
บริษัท เอส คอร์ปอเรชั่น vs บริษัท ซี
หลังจากปรับแต่งแบบสอบถามแล้วเราจำเป็นต้องตรวจสอบว่าดัชนีถูกใช้อย่างไร การบำรุงรักษาดัชนีต้องใช้ CPU และ I / O จำนวนมาก ทุกครั้งที่เราแทรกข้อมูลลงในฐานข้อมูล SQL Server จำเป็นต้องอัปเดตดัชนีด้วยดังนั้นจึงเป็นการดีกว่าที่จะลบออกหากไม่ได้ใช้
เซิร์ฟเวอร์ SQL ให้เรา dm_db_index_usage_stats
DMV เพื่อค้นหาสถิติดัชนี เมื่อเราเรียกใช้รหัส T-SQL ด้านล่างเราจะได้รับสถิติการใช้งานสำหรับดัชนีต่างๆ หากเราพบดัชนีที่ไม่ได้ใช้เลยหรือใช้น้อยครั้งเราสามารถวางดัชนีเพื่อเพิ่มประสิทธิภาพได้
SELECT OBJECT_NAME(IUS.[OBJECT_ID]) AS [OBJECT NAME], DB_NAME(IUS.database_id) AS [DATABASE NAME], I.[NAME] AS [INDEX NAME], USER_SEEKS, USER_SCANS, USER_LOOKUPS, USER_UPDATES FROM SYS.DM_DB_INDEX_USAGE_STATS AS IUS INNER JOIN SYS.INDEXES AS I ON I.[OBJECT_ID] = IUS.[OBJECT_ID] AND I.INDEX_ID = IUS.INDEX_ID
เมื่อตั้งค่าฐานข้อมูลเราจำเป็นต้องเก็บข้อมูลและไฟล์บันทึกแยกกัน เหตุผลหลักคือการเขียนและการเข้าถึงไฟล์ข้อมูลไม่เป็นลำดับในขณะที่การเขียนและการเข้าถึงไฟล์บันทึกเป็นแบบลำดับ หากเราวางไว้ในไดรฟ์เดียวกันเราจะไม่สามารถใช้งานได้อย่างเหมาะสมที่สุด
เมื่อเราซื้อ Storage Area Network (SAN) ผู้ขายอาจให้คำแนะนำเกี่ยวกับวิธีการตั้งค่า แต่ข้อมูลนี้ไม่เป็นประโยชน์เสมอไป เราจำเป็นต้องสนทนาโดยละเอียดกับฮาร์ดแวร์และเครือข่ายของเราเกี่ยวกับวิธีการเก็บข้อมูลและไฟล์บันทึกแยกจากกันและด้วยวิธีที่เหมาะสมที่สุด
งานหลักของผู้ดูแลระบบฐานข้อมูลคือตรวจสอบให้แน่ใจว่าเซิร์ฟเวอร์ที่ใช้งานจริงทำงานได้อย่างราบรื่นและให้บริการลูกค้าได้ดีที่สุด ในการทำให้สิ่งนี้เกิดขึ้นเราจำเป็นต้องรักษาฐานข้อมูลแยกกัน (ถ้าเป็นไปได้บนเครื่องแยกต่างหาก) สำหรับสภาพแวดล้อมต่อไปนี้:
สำหรับฐานข้อมูลการผลิตเราต้องการฐานข้อมูลแบบเต็ม โหมดการกู้คืน และสำหรับฐานข้อมูลอื่นโหมดการกู้คืนอย่างง่ายก็เพียงพอแล้ว
การทดสอบบน ฐานข้อมูลการผลิต จะใส่ภาระจำนวนมากในบันทึกธุรกรรมดัชนี CPU และ I / O นั่นคือเหตุผลที่เราต้องใช้ฐานข้อมูลแยกต่างหากสำหรับการผลิตการพัฒนาการทดสอบและการวิเคราะห์ ถ้าเป็นไปได้ให้ใช้เครื่องแยกกันสำหรับแต่ละฐานข้อมูลเพราะจะลดภาระของ CPU และ I / O
ไฟล์บันทึกต้องมีพื้นที่ว่างเพียงพอสำหรับการดำเนินการตามปกติเนื่องจากการดำเนินการย้ายอัตโนมัติในไฟล์บันทึกใช้เวลานานและอาจบังคับให้การดำเนินการอื่น ๆ รอจนกว่าจะเสร็จสิ้น หากต้องการทราบขนาดไฟล์บันทึกสำหรับแต่ละฐานข้อมูลและจำนวนที่ใช้เราสามารถใช้ DBCC SQLPERF(logspace)
วิธีที่ดีที่สุดในการตั้งค่า tempdb คือใส่ลงในดิสก์แยกต่างหาก เราจำเป็นต้องรักษาขนาดเริ่มต้นให้ใหญ่ที่สุดเท่าที่จะทำได้เพราะเมื่อถึงสถานการณ์การเติบโตอัตโนมัติประสิทธิภาพจะลดลง
ดังที่ได้กล่าวไว้ก่อนหน้านี้เราจำเป็นต้องตรวจสอบให้แน่ใจว่าเซิร์ฟเวอร์ SQL ทำงานบนเครื่องแยกต่างหากโดยเฉพาะอย่างยิ่งหนึ่งที่ไม่มีแอปพลิเคชันอื่น เราจำเป็นต้องเก็บหน่วยความจำบางส่วนสำหรับระบบปฏิบัติการรวมทั้งบางส่วนเพิ่มเติมหากเป็นส่วนหนึ่งของคลัสเตอร์ดังนั้นในกรณีส่วนใหญ่ควรทำประมาณ 2GB
สำหรับสภาพแวดล้อมที่สำคัญของภารกิจความล่าช้าในการรับข้อมูลเพียงมิลลิวินาทีอาจเป็นตัวทำลายข้อตกลง ทวีตขั้นตอนและคำแนะนำที่กล่าวถึงในที่นี้มีไว้สำหรับการปรับแต่งประสิทธิภาพขั้นพื้นฐานเท่านั้น หากเราทำตามขั้นตอนเหล่านี้โดยเฉลี่ยแล้วเราอาจได้รับการปรับปรุงประสิทธิภาพประมาณ 40 ถึง 50 เปอร์เซ็นต์ ในการปรับแต่งประสิทธิภาพ SQL Server ขั้นสูงเราจะต้องเจาะลึกลงไปในแต่ละขั้นตอนที่กล่าวถึงที่นี่
ที่เกี่ยวข้อง: คู่มือ Oracle ไปยัง SQL Server และ SQL Server ไปยัง Oracle Migration