Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Việc cần làm (hoặc không nên làm) đối với số liệu thống kê về thời gian chờ hàng đầu

Một trong những thuật ngữ phổ biến nhất được đưa ra trong các cuộc thảo luận về điều chỉnh hiệu suất SQL Server là số liệu thống kê chờ . Điều này đã có từ rất lâu, ngay cả trước tài liệu Microsoft năm 2006 này, "SQL Server 2005 Waits and Queues".

Chờ đợi hoàn toàn không phải là tất cả, và phương pháp luận này không phải là cách duy nhất để điều chỉnh một thể hiện, đừng bận tâm đến một truy vấn riêng lẻ. Trên thực tế, sự chờ đợi thường vô ích khi tất cả những gì bạn có là truy vấn gây ra chúng, và không có bối cảnh xung quanh, đặc biệt là rất lâu sau thực tế. Điều này là do, khá thường xuyên, điều mà một truy vấn đang chờ đợi không phải là lỗi của truy vấn đó . Giống như bất cứ điều gì, vẫn có những ngoại lệ, nhưng nếu bạn đang chọn một công cụ hoặc tập lệnh chỉ vì nó cung cấp chức năng rất cụ thể này, tôi nghĩ bạn đang tự làm cho mình trở thành kẻ phá hoại. Tôi có xu hướng làm theo một lời khuyên mà Paul Randal đã cho tôi một thời gian trước:

… nói chung tôi khuyên bạn nên bắt đầu với các lần đợi toàn bộ phiên bản. Tôi sẽ không bao giờ bắt đầu khắc phục sự cố bằng cách xem xét các lần chờ truy vấn riêng lẻ.

Đôi khi, có, bạn có thể muốn tìm hiểu sâu hơn về một truy vấn riêng lẻ và xem nó đang chờ đợi điều gì; trên thực tế, Microsoft gần đây đã thêm số liệu thống kê chờ cấp độ truy vấn để hiển thị kế hoạch nhằm trợ giúp phân tích này. Nhưng những con số này thường sẽ không giúp bạn điều chỉnh toàn bộ hiệu suất của phiên bản của bạn, trừ khi chúng giúp chỉ ra điều gì đó cũng sẽ ảnh hưởng đến toàn bộ khối lượng công việc của bạn. Nếu bạn thấy một truy vấn từ hôm qua đã chạy trong 5 phút và nhận thấy rằng kiểu chờ của nó là LCK_M_S , bạn định làm gì với nó bây giờ? Làm cách nào để theo dõi điều gì đã thực sự chặn truy vấn và gây ra kiểu chờ đợi đó? Nó có thể được gây ra bởi một giao dịch không được cam kết vì một số lý do khác, nhưng bạn không thể thấy điều đó nếu bạn không thể thấy trạng thái của toàn bộ hệ thống và chỉ tập trung vào các truy vấn riêng lẻ và sự chờ đợi mà họ đã trải qua.

Jason Hall (@SQLSaurus) đã đề cập đến điều gì đó mà tôi cũng thấy thú vị. Ông nói rằng nếu số liệu thống kê về thời gian chờ ở cấp độ truy vấn là một phần quan trọng trong nỗ lực điều chỉnh, thì phương pháp luận này sẽ được đưa vào Query Store ngay từ đầu. Nó đã được thêm gần đây (trong SQL Server 2017). Nhưng bạn vẫn không nhận được số liệu thống kê về thời gian chờ cho mỗi lần thực hiện; bạn nhận được giá trị trung bình theo thời gian, như thống kê truy vấn và thống kê thủ tục mà bạn thấy trong DMV. Vì vậy, các bất thường đột ngột có thể rõ ràng dựa trên các số liệu khác được ghi lại trên mỗi lần thực thi truy vấn, nhưng không dựa trên thời gian chờ trung bình được rút ra trên tất cả các cuộc hành quyết. Bạn có thể tùy chỉnh phạm vi chờ được tổng hợp lại, nhưng trên các hệ thống bận rộn, điều này vẫn có thể không đủ chi tiết để làm những gì bạn nghĩ rằng nó sẽ làm cho bạn.

Mục đích của bài đăng này là thảo luận về một số kiểu chờ đợi phổ biến hơn mà chúng tôi thấy trong cơ sở khách hàng của mình và những hành động bạn có thể (và không nên) thực hiện khi chúng xảy ra. Chúng tôi có cơ sở dữ liệu về số liệu thống kê chờ ẩn danh mà chúng tôi đã thu thập được từ khách hàng Cloud Sync của mình trong một thời gian khá dài và kể từ tháng 5 năm 2017, chúng tôi đã cho mọi người thấy những thống kê này trông như thế nào trên Thư viện SQLskills Waits.

Paul nói về lý do đằng sau thư viện và cũng như về sự tích hợp của chúng tôi với dịch vụ miễn phí này. Về cơ bản, bạn tra cứu kiểu chờ đợi mà bạn đang trải qua hoặc tò mò, và anh ấy giải thích ý nghĩa của nó và những gì bạn có thể làm với nó. Chúng tôi bổ sung thông tin định tính này bằng một biểu đồ cho thấy mức độ phổ biến của thời gian chờ đợi hiện tại trong cơ sở người dùng của chúng tôi, so sánh điều đó với tất cả các loại chờ đợi khác mà chúng tôi thấy, vì vậy bạn có thể nhanh chóng cho biết liệu bạn đang đối phó với loại chờ thông thường hay điều gì đó hơn một chút kỳ lạ. (Xin lưu ý rằng SQL Sentry không bao gồm phần mềm, nền và hàng đợi gây nhiễu và hầu hết các tập lệnh ngoài đó đều lọc ra, như WAITFOR hoặc LAZYWRITER_SLEEP - đây không phải là nguồn gây ra các vấn đề về hiệu suất.)

Đây là biểu đồ ví dụ cho CXPACKET , kiểu chờ phổ biến nhất hiện có:

Tôi bắt đầu đi xa hơn điều này một chút, vạch ra một số kiểu chờ đợi phổ biến hơn và ghi nhận một số thuộc tính mà chúng đã chia sẻ. Được dịch thành các câu hỏi mà một bộ dò có thể có về kiểu chờ đợi mà họ đang gặp phải:

  • Có thể giải quyết kiểu chờ đợi ở cấp độ truy vấn không?
  • Triệu chứng cốt lõi của việc chờ đợi có thể ảnh hưởng đến các truy vấn khác không?
  • Có khả năng bạn sẽ cần thêm thông tin bên ngoài ngữ cảnh của một truy vấn và các kiểu chờ đợi mà nó đã trải qua để "giải quyết" vấn đề không?

Khi tôi bắt đầu viết bài đăng này, mục tiêu của tôi chỉ là nhóm các kiểu chờ đợi phổ biến nhất lại với nhau, và sau đó bắt đầu ghi nhanh các ghi chú về chúng liên quan đến các câu hỏi ở trên. Jason lấy những cái phổ biến nhất từ ​​thư viện, và sau đó tôi vẽ một số vết cào gà lên bảng trắng, sau đó tôi đã thu dọn lại một chút. Nghiên cứu ban đầu này dẫn đến một cuộc nói chuyện mà Jason đã đưa ra trên TechOutbound SQL Cruise gần đây nhất ở Alaska. Tôi hơi xấu hổ vì anh ấy đã nói chuyện với nhau nhiều tháng trước khi tôi có thể hoàn thành bài đăng này, vì vậy hãy tiếp tục với nó. Dưới đây là những sự chờ đợi hàng đầu mà chúng tôi thấy (phần lớn phù hợp với cuộc khảo sát của Paul từ năm 2014), câu trả lời của tôi cho những câu hỏi trên và một số bình luận về mỗi câu hỏi:

Để tương tác với các liên kết trong bảng bên dưới, vui lòng truy cập trang này trên một màn hình rộng hơn.

10 :LCK_M_X Bị chặn khi cố gắng cập nhật hàng, trang, phân vùng, v.v. bằng một khóa riêng. Điều này có thể là do khóa giản đồ (ví dụ:xây dựng lại ngoại tuyến), báo cáo từ các gợi ý khóa rõ ràng, các giao dịch kéo dài hoặc một loạt các lý do khác. Điều này thường có thể là do một chỉ mục "nóng" - có thể rõ ràng từ truy vấn đó là chỉ mục nào hoặc có các gợi ý rõ ràng như TABLOCKX , nhưng nó có thể không. Loại chờ đợi một mình sẽ không cho bạn biết bất kỳ điều gì trong số đó; bạn sẽ cần nắm bắt phiên bản dài hạn của truy vấn trong hành động và điều tra những thứ như kế hoạch thực thi, sys.dm_tran_locks , sys.dm_os_waiting_tasks và thậm chí có thể theo một chuỗi chặn đến người dẫn đầu.

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác?
Cần thêm thông tin bên ngoài?
9 :LCK_M_U Về cơ bản giống với # 10, ngoại trừ đây chỉ là khóa cập nhật thông thường, không phải là khóa độc quyền.

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác?
Cần thêm thông tin bên ngoài?
8 :WRITELOG Bị chặn khi chờ ghi khối nhật ký vào đĩa. Mặc dù bạn có thể tranh luận rằng sự chờ đợi này xảy ra bởi vì bạn chỉ đang ghi quá nhiều vào nhật ký, nhưng đây là một vấn đề cơ sở dữ liệu hoặc toàn hệ thống gần như chắc chắn ảnh hưởng nhiều hơn là chỉ truy vấn hiện tại mà bạn đang khắc phục sự cố. Có thể bạn có quá nhiều giao dịch khổng lồ liên tục ghi vào nhật ký, trong trường hợp đó, bạn có thể xem xét các thao tác ghi phân khúc, thay đổi các quy trình cắt / tải để nâng cấp, hoặc thậm chí trì hoãn độ bền hoặc OLTP trong bộ nhớ. Số lượng VLF cao có thể góp phần vào loại chờ đợi này, cũng như đạt đến giới hạn ghi đồng thời tối đa và các lần chờ cấp truy vấn của bạn cũng sẽ không cho bạn biết điều đó. Nó cũng có thể trở nên phổ biến hơn nếu bạn đang sử dụng công nghệ HA đồng bộ, như phản chiếu hoặc Nhóm sẵn sàng. Điều này có xu hướng liên quan đến I / O chậm nói chung, trong trường hợp đó, bạn nên cân nhắc chuyển nhật ký sang SSD hoặc tốt hơn, nếu có thể.

Thông tin chi tiết trong thư viện và xem các bài đăng này từ Paul (phần một | phần hai), Erin Stellato và Tim Radney.

Có thể giải quyết được ở cấp độ truy vấn? Không
Có thể ảnh hưởng đến các truy vấn khác?
Cần thêm thông tin bên ngoài? Có lẽ
7 :LCK_M_IX Giống như # 9 và # 10 ở trên, nhưng lần này là khóa dành riêng cho mục đích (mà Klaus Aschenbrenner thảo luận ở đây).

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác?
Cần thêm thông tin bên ngoài?
6 :LATCH_EX Đang đợi chốt độc quyền trên cấu trúc dữ liệu không phải trang như bộ đệm trang hoặc tệp dữ liệu hoặc nhật ký. Các ví dụ bao gồm đợi tệp nhật ký tự động duyệt hoặc thậm chí là NOLOCK các chốt được chia sẻ của truy vấn đang trì hoãn cập nhật. Bạn sẽ cần tìm kiếm những thứ này bằng cách sử dụng sys.dm_os_waiting_taskssys.dm_os_latch_stats , và sau đó tra cứu lớp chốt trong Thư viện lớp chốt, nhưng chỉ làm như vậy nếu đây là lần chờ đợi hàng đầu trên hệ thống của bạn và đang ảnh hưởng đến một số lượng lớn các truy vấn.

Thông tin chi tiết trong thư viện.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác? Có lẽ
Cần thêm thông tin bên ngoài?
5 :ASYNC_NETWORK_IO Đang chờ xác nhận rằng dữ liệu đã được gửi bởi TDS. Thường thì điều này bị hiểu sai là một chỉ báo về băng thông mạng chậm; Tôi hình ảnh một DBA hét lên với cả văn phòng của mình, "Ngừng tải xuống các tệp lớn!" Đây hầu như không bao giờ là một vấn đề mạng; thường là do sự chậm trễ trong quá trình xử lý máy khách, nơi xử lý giống như con trỏ, MARS, máy chủ được liên kết hoặc máy khách không đủ năng lực đang hoạt động. Thông thường, nó đang cố gắng hiển thị 50 tỷ hàng trong lưới SSMS trên máy có RAM 4 GB hoặc một ứng dụng phân trang kéo toàn bộ bảng, hiển thị 50 hàng, rồi tạm dừng, chờ bạn nhấp vào tiếp theo. Ứng dụng không thể (hoặc sẽ không) theo kịp và Máy chủ SQL đăng ký kiểu chờ này vì nó đang chờ ứng dụng tiêu thụ nhiều hàng hơn.

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác? Có thể
Cần thêm thông tin bên ngoài?
4 :SOS_SCHEDULER_YIELD Điều này chỉ có nghĩa là một luồng đã tự nguyện sinh ra ở cuối lượng tử 4ms của nó. Nó có thể cho biết thời gian quét, sắp xếp hoặc biên dịch không mong muốn; hoặc một máy ảo được cấp nguồn / đăng ký quá mức. Nếu đây là một hàng đầu đợi đã, là một vấn đề mới và có thể liên quan đến vấn đề hiệu suất thực tế, hãy xem các truy vấn này trong sys.dm_exec_requests , xem kế hoạch hiện tại có đang thực hiện quét hoặc sắp xếp lớn có thể tránh được không và nếu không có nguyên nhân rõ ràng, hãy tìm hiểu sâu hơn.

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác?
Cần thêm thông tin bên ngoài? Không
3 :PAGEIOLATCH_SH Đang đợi để đọc một trang dữ liệu trước tiên phải được đọc từ đĩa. Điều này có vẻ như là sự cố với hệ thống con I / O và bạn nên phát hiện vấn đề này thông qua độ trễ trong sys.dm_io_virtual_file_stats . Nhưng thường là do không đủ bộ nhớ - hoặc những thứ đang đẩy các trang ra khỏi bộ nhớ, chẳng hạn như DBCC DROPCLEANBUFFERS rõ ràng cuộc gọi hoặc chỉ quét quá nhiều bảng lớn, khác nhau. Thêm bộ nhớ nếu có thể, di chuyển cơ sở dữ liệu hoặc ứng dụng ngốn bộ nhớ khác sang máy chủ khác hoặc điều chỉnh các truy vấn để loại bỏ các lần quét không cần thiết.

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác? Có lẽ
Cần thêm thông tin bên ngoài?
2 :LCK_M_S Đang đợi để có được khóa dùng chung trên một hàng, trang, phân vùng, v.v. Điều này có thể xảy ra trong thời gian ngắn khi khóa S được thực hiện trên toàn bộ cơ sở dữ liệu (ví dụ:ai đó đang thay đổi cài đặt cơ sở dữ liệu) hoặc kịch bản "người viết chặn người đọc" cơ bản và phổ biến hơn. Nếu đây là lần chờ đợi hàng đầu và bạn có thể liên hệ nó với các vấn đề hiệu suất cụ thể trong khối lượng công việc của mình, hãy cố gắng nắm bắt (các) tài nguyên bị ảnh hưởng thông qua sys.dm_os_waiting_taskssys.dm_tran_locks . Một biện pháp giảm thiểu có thể được sử dụng Ảnh chụp đã cam kết đã đọc, nhưng bạn cần lưu ý về tác động đối với tempdb.

Thông tin chi tiết khác trong thư viện và trong bài đăng này về phản ứng giật đầu gối.

Có thể giải quyết được ở cấp độ truy vấn? Có thể
Có thể ảnh hưởng đến các truy vấn khác?
Cần thêm thông tin bên ngoài?
1 :CXPACKET Cho đến nay, kiểu chờ được nhắc đến nhiều nhất và bị hiểu nhầm đang tồn tại. Hầu hết thời gian, điều này chỉ có nghĩa là sự song song đang xảy ra. Phản ứng giật đầu gối là đặt máy chủ MAXDOP đến 1. Đừng làm điều này.

Trong thời gian dài nhất, CXPACKET kết hợp cả chờ song song "tốt" (luồng bộ điều khiển chờ tất cả các luồng kết thúc) và chờ song song "xấu" (một hoặc nhiều luồng nhà sản xuất đã kết thúc nhưng đang chờ các nhà sản xuất khác hoàn thành). Sự kết hợp này khiến rất khó xác định xem CXPACKET chờ đợi là một vấn đề hoặc chỉ là một thuộc tính của khối lượng công việc song song cao.

Trong SQL Server 2016 SP2, 2017 CU3 và Azure SQL Database, điều này đã thay đổi. CXPACKET đã chuyển các lượt chờ song song "tốt" thành kiểu chờ lành tính của riêng chúng, CXCONSUMER (chi tiết tại đây). Trong các phiên bản mới hơn này, kiểu chờ mới này nên được bỏ qua nhưng, nếu CXPACKET vẫn ở mức cao, nhiều khả năng bạn đang gặp phải hiện tượng song song "kém" (thường là phân phối lệch do thống kê không hợp lệ hoặc ước tính không hợp lệ).

Trong cả hai trường hợp, bạn có thể xác định nguyên nhân và thực hiện các bước khắc phục, theo lời khuyên của Paul tại đây và tại đây, đồng thời xem thêm chi tiết trong thư viện.

Có thể giải quyết được ở cấp độ truy vấn?
Có thể ảnh hưởng đến các truy vấn khác? Có thể
Cần thêm thông tin bên ngoài?

Tóm tắt

Trong hầu hết các trường hợp này, tốt hơn là bạn nên xem xét các lượt chờ ở cấp phiên bản và chỉ tập trung vào các lượt chờ ở cấp độ truy vấn khi bạn đang khắc phục sự cố các truy vấn cụ thể có vấn đề về hiệu suất bất kể loại chờ nào. Đây là những thứ xuất hiện vì những lý do khác, như thời lượng dài, CPU cao hoặc I / O cao và không thể giải thích bằng những thứ đơn giản hơn (như quét chỉ mục theo cụm khi bạn đang mong đợi một tìm kiếm).

Ngay cả ở cấp độ cá thể, đừng đuổi theo mọi sự chờ đợi mà trở thành sự chờ đợi hàng đầu trên hệ thống của bạn - bạn sẽ LUÔN LUÔN có một sự chờ đợi hàng đầu, và bạn sẽ không bao giờ có thể ngừng theo đuổi nó. Đảm bảo rằng bạn bỏ qua các lần chờ lành tính (Paul giữ một danh sách) và chỉ lo lắng về các lần chờ có thể liên quan đến sự cố hiệu suất thực tế mà bạn đang gặp phải. Nếu CXPACKET chờ đợi cao, vì vậy những gì? Có bất kỳ triệu chứng nào khác ngoài việc con số đó là "cao" hoặc đứng đầu danh sách không?

Tất cả đều giải thích tại sao bạn đang khắc phục sự cố ngay từ đầu. Có phải một người dùng đang phàn nàn về một trường hợp duy nhất của truy vấn giả mạo không? Máy chủ của bạn có đang trên đầu gối không? Một cái gì đó ở giữa? Trong trường hợp đầu tiên, chắc chắn, biết lý do tại sao truy vấn chậm có thể hữu ích, nhưng khá tốn kém để theo dõi (đừng nhớ giữ vô thời hạn) tất cả các lần chờ được liên kết với mỗi truy vấn, cả ngày, hàng ngày, nếu bạn có muốn quay lại và xem lại chúng sau. Nếu đó là một vấn đề phổ biến riêng biệt với truy vấn đó, bạn sẽ có thể xác định điều gì làm cho truy vấn đó chậm bằng cách chạy lại và thu thập kế hoạch thực thi, thời gian biên dịch và các chỉ số thời gian chạy khác. Nếu đó là sự việc xảy ra một lần vào thứ Ba tuần trước, cho dù bạn có chờ đợi phiên bản truy vấn đơn lẻ đó hay không, bạn có thể không giải quyết được vấn đề mà không có thêm ngữ cảnh. Có thể đã có sự ngăn chặn, nhưng bạn sẽ không biết bằng cách nào hoặc có thể có sự gia tăng đột biến I / O, nhưng bạn sẽ phải tìm hiểu vấn đề đó một cách riêng biệt. Riêng kiểu chờ đợi thường không cung cấp đủ thông tin ngoại trừ, tốt nhất là một con trỏ đến một thứ khác.

Tất nhiên, tôi cũng cần kiếm tiền giữ của mình ở đây. Sản phẩm hàng đầu của chúng tôi, SQL Sentry, có một cách tiếp cận toàn diện để giám sát. Chúng tôi thu thập số liệu thống kê về thời gian chờ trên toàn trường hợp, phân loại chúng cho bạn và vẽ biểu đồ trên trang tổng quan của chúng tôi:

Bạn có thể tùy chỉnh cách phân loại bất kỳ sự chờ đợi riêng lẻ nào và liệu danh mục đó có hiển thị trên trang tổng quan hay không. Bạn có thể so sánh số liệu thống kê về thời gian chờ hiện tại với các đường cơ sở được tích hợp sẵn hoặc tùy chỉnh và thậm chí thiết lập các cảnh báo hoặc hành động khi chúng vượt quá một số độ lệch xác định so với đường cơ sở. Và, có lẽ quan trọng nhất, bạn có thể xem xét một điểm dữ liệu trong quá khứ và đồng bộ hóa toàn bộ trang tổng quan đến thời điểm đó, vì vậy bạn có thể nắm bắt tất cả bối cảnh xung quanh và bất kỳ tình huống nào khác có thể ảnh hưởng đến vấn đề. Khi bạn tìm thấy những thứ chi tiết hơn để tập trung vào, như chặn, độ trễ đĩa cao hoặc các truy vấn có I / O cao hoặc thời lượng dài, bạn có thể đi sâu vào các chỉ số đó và đi sâu vào gốc rễ của vấn đề khá nhanh.

Để biết thêm thông tin về cả hai phương pháp tiếp cận thống kê thời gian chờ chung và giải pháp của chúng tôi cụ thể, bạn có thể xem sách trắng của Kevin Kline, Khắc phục sự cố Thống kê chờ máy chủ SQL và bạn có thể tải xuống hội thảo trên web gồm hai phần do Paul Randal, Andy Yun (@SQLBek) trình bày, và Andy Mallon (@AMtwo):

  • Phần 1:Khắc phục sự cố Hiệu suất Sử dụng Thống kê Chờ
  • Phần 2:Phân tích Nhanh Thống kê Chờ với SentryOne

Và nếu bạn muốn thử nghiệm Nền tảng SentryOne, bạn có thể bắt đầu tại đây với ưu đãi trong thời gian giới hạn:

Tải xuống bản dùng thử miễn phí 15 ngày


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Trận đấu gần nhất, Phần 2

  2. Làm việc với Giao diện người dùng JavaFX và Ứng dụng JDBC

  3. Hệ thống tự động gửi email để gửi báo cáo tóm tắt cơ sở dữ liệu

  4. Làm thế nào để cài đặt SQLcl trên windows?

  5. Cách đổi tên cột trong SQL