2014-10-10 12 views
7

Tôi đã làm việc trên Coldfusion/MS SQL trong nhiều năm và đây là một trong những vấn đề kỳ lạ nhất mà tôi từng thấy. Vấn đề chính nó đã được giải quyết nhưng tôi không thực sự hiểu những gì đã xảy ra; câu hỏi này đang cố gắng để có được một ý tưởng rõ ràng về nguyên nhân có thể xảy ra.Truy vấn chạy chậm, CF 9 & MSSQL 2008; kế hoạch thực thi bị hỏng?

Vấn đề

Trong một môi trường sản xuất ổn định, không có lý do rõ ràng, một truy vấn bắt đầu trở lại trong khoảng 1.000-1.500 ms (chậm hơn bình thường khoảng 10 lần). Tôi đã có thể để cô lập nó như thế này:

<cfquery datasource="#ds#" name="query"> 
    select 1 
    from eLearning.v_courseCompletion cc 
    where 
     cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and 
     cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and 
     cc.currentCourseCompleted = 1 
</cfquery> 

Có gì lạ là, hành vi này là trầm trọng hơn khi trong một vòng lặp, ngay cả khi có một sự lặp lại đơn, như trong ví dụ này:

<cfloop from="1" to="1" index="i"> 
    <cfquery datasource="#ds#" name="query"> 
     select 1 
     from eLearning.v_courseCompletion cc 
     where 
     cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and 
     cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and 
     cc.currentCourseCompleted = 1 
    </cfquery> 
</cfloop> 

Điều này phải chính xác giống như trên, phải không? Vòng lặp sẽ không có hiệu lực nhưng thay vào đó, thử nghiệm này chạy chậm hơn khoảng 10 lần, trở lại từ 7.000-16.000 ms. Đây là cách phát hiện vấn đề; truy vấn (được chôn trong một phương thức đối tượng) đã được gọi từ cơ thể của một vòng lặp, nếu vòng lặp lặp lại nhiều hơn 5 hoặc 6 lần yêu cầu sẽ hết thời gian chờ.

Với tôi, điều này cho thấy một vấn đề ở phía Coldfusion nhưng khởi động lại dịch vụ, hoặc thực sự là máy, không làm gì cả.

Trong khi đó, một khi bị cô lập, tôi nhận thấy rằng việc thực hiện bất kỳ thay đổi nào đối với truy vấn đã khiến hiệu suất trở về mức dự kiến, khoảng 150-190 ms. Ví dụ:

  • Thay đổi các lĩnh vực được lựa chọn (. Tức là select *)
  • Loại bỏ các bí danh bảng (cc)
  • Thay thế hoặc <cfqueryparam> với một giá trị inline
  • Loại bỏ bất kỳ các điều kiện

Bất kỳ thay đổi nào trong số này "đã khắc phục" sự cố nhưng khi chạy truy vấn ban đầu, sự cố về hiệu suất sẽ trở lại.

Giải pháp

Tại thời điểm này tôi đoán kế hoạch thực hiện các truy vấn đã bị hỏng hoặc một cái gì đó, đã làm some Googling, và chạy DBCC FREEPROCCACHE chống lại các máy chủ DB. Điều này khắc phục sự cố ngay lập tức. Tuyệt vời, vấn đề giải quyết ....

Các Câu hỏi

Kể từ đó, mặc dù tôi đã thực hiện một chút nghiên cứu thêm và sự đồng thuận dường như là kế hoạch thực hiện "không bị hỏng". Có một some talk của similar problems xảy ra với các thủ tục được lưu trữ và parameter sniffing nhưng tôi không sử dụng bất kỳ sp nào tại đây. Chúng tôi đang lựa chọn từ một cái nhìn khá phức tạp mặc dù (eLearning.v_courseCompletion) với tham gia lồng nhau. Đó có phải là vấn đề không?

Về cơ bản, điều gì thực sự đã xảy ra ở đây? Làm thế nào để tôi ngăn nó lại xảy ra?

.. và kết nối với vòng lặp trong CF là gì?!?

phiên bản

  • Coldfusion 9.0.2.282541 (64 bit)
  • SQL Server Express 10.50.4297 (64 bit)
  • Cả hai máy chủ là Win Server 2008 R2 Datacenter (64 bit)

Trả lời

6

Bạn đang sử dụng quy trình được lưu trữ trong mui xe khi bạn sử dụng cfqueryparam. Khi bạn không sử dụng cfqueryparam, truy vấn của bạn chỉ được gửi dưới dạng truy vấn hàng loạt "văn bản miễn phí". Khi bạn sử dụng cfqueryparam, bạn đang gửi truy vấn của mình vào để được thực thi bằng cách sử dụng sp_executeSQL() mà chính nó sẽ gửi thân truy vấn của bạn dưới dạng tham số. Điều này cho phép kế hoạch truy vấn cache. Nếu nó thấy cùng một truy vấn, nó sẽ sử dụng số liệu thống kê mà nó đã lưu cho kế hoạch cụ thể đó. Điều này có nghĩa, nếu nó chạy với một số dữ liệu thực sự kỳ quặc và có ý tưởng tồi để thực hiện truy vấn, các lần lặp tiếp theo sẽ sử dụng cùng một kế hoạch, đó là "kế hoạch xấu" cho 99% trường hợp sử dụng truy vấn này, nhưng có lẽ là một kế hoạch tốt cho một ví dụ kỳ lạ đó.

Mỗi truy vấn được thực thi với SQL sp_execute cũng trả về một số xử lý mà trình điều khiển JDBC có thể sử dụng để chỉ cho SQL biết kế hoạch nào có thể sử dụng, về cơ bản là một lối tắt. Điều này được gọi là "báo cáo tổng hợp tối đa" trong cài đặt DSN của bạn trong CFadmin. Có được thiết lập là 0 hoặc 1000 không ảnh hưởng đến thực tế là bạn sẽ tận dụng bộ nhớ cache kế hoạch với sp_executeSQL.

http://blogs.msdn.com/b/turgays/archive/2013/09/18/exec-vs-sp-executesql.aspx

StackOverflow đã có một cuộc biểu tình tốt về điều này, nếu một người sử dụng sức mạnh đặc biệt sẽ tải trang tài khoản của họ với hàng triệu người phù hiệu và các điểm trước khi số liệu thống kê truy vấn được xây dựng, nó sẽ mess lên số liệu thống kê cho mỗi khác người dùng có một vài trăm điểm trở lên và một số huy hiệu, làm cho trang chậm đối với người đó.

+0

Ah tuyệt vời, điều đó có ý nghĩa rất nhiều. Bất kỳ cái nhìn sâu sắc vào lý do tại sao chạy nó từ bên trong một vòng lặp (thậm chí 1 lần lặp) sẽ ảnh hưởng đến hiệu suất rất nhiều? Cảm ơn – Molomby

+0

Không, vòng lặp không có vẻ giống như thủ phạm. Tôi sẽ đổ lỗi cho một số trường hợp khác mà vòng lặp cung cấp, chẳng hạn như biến chỉ mục hoặc thứ gì đó làm cho vòng lặp có vẻ như nó là để đổ lỗi. Ngoài ra, bạn hầu như luôn có thể thoát khỏi việc không chạy cfquery trong một vòng lặp. Có rất ít lần điều này thực sự có ý nghĩa. –

+0

Cảm ơn bạn đã theo dõi nhưng tôi đảm bảo với bạn không có gì khác trong vòng lặp có thể (nên?) Đang gây ra điều này; các khối mã được đăng ở trên đều nằm ngoài các trường hợp thử nghiệm của tôi (cộng với 'getTickCount()' trước và sau). Biến chỉ mục (hoặc mục) của vòng lặp không được tham chiếu chút nào bởi truy vấn và không có gì khác trong thân vòng lặp. Có lẽ một cái gì đó đang đi haywire trong quá trình biên dịch vòng sang Java? Nếu tôi có thể tái tạo vấn đề, tôi sẽ đào sâu hơn một chút. – Molomby

Các vấn đề liên quan