Hình ảnh © Mark Boyle | Ngày Hội đồng NSW của Úc.
Tài sản hình ảnh của (các) nghệ sĩ tương ứng. Mọi quyền được bảo lưu.
AT TIME ZONE là một tính năng thú vị và tôi mới để ý đến nó cho đến gần đây, mặc dù Microsoft đã có một trang về nó từ tháng 12.
Tôi sống ở Adelaide ở Úc. Và giống như hơn một tỷ người khác trên thế giới, người dân Adelaide phải đối mặt với việc sống theo múi giờ nửa giờ. Vào mùa đông, chúng tôi là UTC + 9:30 và vào mùa hè, chúng tôi là UTC + 10:30. Ngoại trừ việc nếu bạn đang đọc cuốn sách này ở Bắc bán cầu, bạn cần phải nhớ rằng "mùa đông", ý tôi là từ tháng 4 đến tháng 10. Thời gian mùa hè là từ tháng 10 đến tháng 4, và ông già Noel ngồi trên bãi biển với đồ uống lạnh, mồ hôi nhễ nhại qua bộ đồ đỏ dày cộp và bộ râu. Tất nhiên, trừ khi anh ấy ra ngoài cứu mạng.
Trong nước Úc, chúng tôi có ba múi giờ chính (miền Tây, miền Trung và miền Đông), nhưng múi giờ này kéo dài đến năm múi giờ vào mùa hè, vì ba tiểu bang kéo dài đến tận cùng phía bắc của Úc (WA, Qld và NT) không cố gắng tiết kiệm bất kỳ ánh sáng ban ngày. Chúng đủ gần với đường xích đạo để không cần quan tâm hoặc những thứ tương tự. Thật là thú vị cho sân bay Gold Coast, nơi có đường băng cắt qua biên giới NSW-QLD.
Máy chủ cơ sở dữ liệu thường chạy trong UTC, vì đơn giản là dễ dàng hơn khi không phải đối phó với việc chuyển đổi giữa UTC và cục bộ (và ngược lại) trong SQL Server. Nhiều năm trước, tôi nhớ đã phải sửa một báo cáo liệt kê các sự cố xảy ra cùng với thời gian phản hồi (tôi đã viết blog về điều này kể từ đó). Việc đo SLA khá đơn giản - tôi có thể thấy rằng một sự cố đã xảy ra trong giờ làm việc của khách hàng và họ đã phản hồi trong vòng một giờ. Tôi có thể thấy rằng một sự cố khác đã xảy ra ngoài giờ làm việc và phản hồi trong vòng hai giờ. Vấn đề xảy ra khi một báo cáo được tạo vào cuối khoảng thời gian khi múi giờ thay đổi, khiến một sự cố thực sự xảy ra lúc 5:30 chiều (ngoài giờ) được liệt kê như thể nó đã xảy ra lúc 4:30 chiều (trong giờ) . Phản hồi mất khoảng 90 phút, điều đó không sao, nhưng báo cáo lại hiển thị khác.
Tất cả điều này đã được khắc phục trong SQL Server 2016.
Cách sử dụng AT TIME ZONE trong SQL Server 2016
Giờ đây, với AT TIME ZONE, thay vì nói:'20160101 00:00 +10:30', tôi có thể bắt đầu bằng một giá trị ngày giờ không có chênh lệch múi giờ và sử dụng AT TIME ZONE để giải thích rằng nó ở Adelaide.
CHỌN CHUYỂN ĐỔI (datetime, '20160101 00:00') TẠI Múi giờ 'Cen. Giờ chuẩn Úc '; - 2016-01-01 00:00:00.000 + 10:30
Và điều này có thể được chuyển đổi sang giờ Mỹ bằng cách thêm lại TẠI TIME ZONE.
CHỌN CHUYỂN ĐỔI (datetime, '20160101 00:00') TẠI Múi giờ 'Cen. Giờ chuẩn Úc 'AT TIME ZONE' Giờ chuẩn miền Đông Hoa Kỳ '; - 2015-12-31 08:30:00.000 -05:00
Bây giờ, tôi biết điều này còn dài hơn rất nhiều. Và tôi cần chuyển đổi rõ ràng chuỗi thành datetime, để tránh lỗi nói:
Kiểu dữ liệu đối số varchar không hợp lệ đối với đối số 1 của hàm AT TIME ZONE.Nhưng bất chấp sự dài dòng của nó, tôi thích nó, bởi vì tôi không cần phải tìm ra rằng Adelaide ở +10:30, hay miền Đông là -5:00 - tôi chỉ cần biết múi giờ theo tên. Việc tìm hiểu xem có nên áp dụng chế độ tiết kiệm ánh sáng ban ngày hay không đã được giải quyết cho tôi và tôi không phải thực hiện bất kỳ chuyển đổi nào từ địa phương sang UTC để thiết lập một số đường cơ sở.
Nó hoạt động bằng cách sử dụng sổ đăng ký Windows, có tất cả thông tin trong đó, nhưng đáng buồn thay, nó không hoàn hảo khi nhìn lại thời gian. Úc đã thay đổi ngày vào năm 2008 và Hoa Kỳ đã thay đổi ngày vào năm 2005 - cả hai quốc gia đều tiết kiệm ánh sáng ban ngày trong năm. AT TIME ZONE hiểu điều này. Nhưng dường như không đánh giá cao điều đó ở Úc vào năm 2000, nhờ Thế vận hội Sydney, Úc đã bắt đầu tiết kiệm ánh sáng ban ngày sớm hơn khoảng hai tháng. Điều này hơi bực bội một chút nhưng đó không phải lỗi của SQL - chúng ta cần đổ lỗi cho Windows vì điều đó. Tôi đoán cơ quan đăng ký Windows không nhớ bản sửa lỗi đã xuất hiện vào khoảng năm đó. (Lưu ý cho bản thân:Tôi có thể cần nhờ ai đó trong nhóm Windows sửa lỗi đó…)
Tuy nhiên, tính hữu ích vẫn tiếp tục!
Tên múi giờ đó thậm chí không cần phải là một hằng số. Tôi có thể chuyển các biến vào và thậm chí sử dụng các cột:
WITH PeopleAndTZs AS (SELECT * FROM (VALUES ('Rob', 'Cen. Giờ chuẩn Úc'), ('Paul', 'Giờ chuẩn New Zealand'), ('Aaron', 'Giờ chuẩn miền Đông Hoa Kỳ') )) t (người, tz)) CHỌN tz. someone, SYSDATETIMEOFFSET () AT TIME ZONE tz.tz FROM PeopleAndTZs tz; / * Rob 2016-07-18 18:29:11.9749952 +09:30 Paul 2016-07-18 20:59:11.9749952 +12:00 Aaron 2016-07-18 04:59:11.9749952-04:00 * /
(Bởi vì tôi đã chạy nó ngay trước 6:30 chiều ở đây ở Adelaide, tức là gần 9 giờ tối ở New Zealand, nơi Paul đang ở và gần 5 giờ sáng nay ở phía đông nước Mỹ, nơi Aaron đang ở.)
Điều này sẽ cho phép tôi dễ dàng biết được giờ của mọi người dù họ ở đâu trên thế giới và xem ai sẽ là người tốt nhất để phản hồi một số vấn đề mà không cần phải thực hiện bất kỳ chuyển đổi ngày giờ thủ công nào. Và thậm chí hơn thế nữa, nó sẽ để tôi làm điều đó cho những người trong quá khứ. Tôi có thể có một báo cáo phân tích múi giờ nào sẽ cho phép số lượng sự kiện xảy ra nhiều nhất trong giờ làm việc.
Các múi giờ đó được liệt kê trong sys.time_zone_info
, cùng với độ lệch hiện tại là bao nhiêu và liệu chế độ tiết kiệm ánh sáng ban ngày hiện có được áp dụng hay không.
tên | current_utc_offset | is_currently_dst |
---|---|---|
Giờ chuẩn Singapore | +08:00 | 0 |
W. Giờ chuẩn Úc | +08:00 | 0 |
Giờ chuẩn Đài Bắc | +08:00 | 0 |
Giờ chuẩn Ulaanbaatar | +09:00 | 1 |
Giờ chuẩn Bắc Triều Tiên | +08:30 | 0 |
Aus Central W. Giờ chuẩn | +08:45 | 0 |
Giờ chuẩn Transbaikal | +09:00 | 0 |
Giờ chuẩn Tokyo | +09:00 | 0 |
Lấy mẫu các hàng từ sys.time_zone_info
Tôi chỉ thực sự quan tâm đến tên là gì, nhưng dù sao. Và thật thú vị khi thấy rằng có một múi giờ được gọi là "Aus Central W. Giờ chuẩn" nằm trên một phần tư giờ. Đi tìm con số. Cũng cần lưu ý rằng các địa điểm được gọi bằng tên Giờ chuẩn của chúng, ngay cả khi chúng hiện đang quan sát DST. Chẳng hạn như Ulaanbaatar trong danh sách đó ở trên, không được liệt kê là Giờ ban ngày của Ulaanbaatar. Điều này có thể khiến mọi người lặp lại khi họ bắt đầu sử dụng AT TIME ZONE.
AT TIME ZONE có thể gây ra sự cố về hiệu suất không?
Bây giờ, tôi chắc chắn rằng bạn đang tự hỏi tác động của việc sử dụng AT TIME ZONE có thể như thế nào đối với việc lập chỉ mục.
Về hình thức của kế hoạch, nó không khác gì đối với việc xử lý datetimeoffset nói chung. Nếu tôi có các giá trị ngày giờ, chẳng hạn như trong cột AdventureWorks Sales.SalesOrderHeader.OrderDate (mà tôi đã tạo chỉ mục có tên rf_IXOD), thì hãy chạy cả truy vấn này:
chọn OrderDate, SalesOrderID từ Sales.SalesOrderHeader trong đó OrderDate> =convert (datetime, '20110601 00:00') tại múi giờ 'Giờ chuẩn miền Đông Hoa Kỳ' và OrderDateVà truy vấn này:
chọn OrderDate, SalesOrderID từ Sales.SalesOrderHeader trong đó OrderDate> =convert (datetimeoffset, '20110601 00:00 -04:00') và OrderDateTrong cả hai trường hợp, bạn nhận được các kế hoạch giống như sau:
Nhưng nếu chúng ta khám phá kỹ hơn một chút, thì có một vấn đề.
Phương thức sử dụng AT TIME ZONE không sử dụng tốt các số liệu thống kê. Nó cho rằng sẽ thấy 5.170 hàng thoát ra từ Tìm kiếm chỉ mục đó, trong khi thực tế chỉ có 217. Tại sao lại là 5.170? Chà, bài đăng gần đây của Aaron, "Chú ý đến các ước tính", giải thích điều đó, bằng cách tham khảo bài đăng "Ước tính số lượng thẻ cho nhiều dự đoán" của Paul. 5.170 là 31.465 (hàng trong bảng) * 0,3 * sqrt (0,3).
Truy vấn thứ hai làm đúng, ước tính 217. Bạn thấy đấy, không có chức năng nào liên quan.
Điều này có lẽ là đủ công bằng. Ý tôi là - tại thời điểm nó đang tạo ra kế hoạch, nó sẽ không yêu cầu cơ quan đăng ký cung cấp thông tin mà nó cần, vì vậy nó thực sự không biết có bao nhiêu để ước tính. Nhưng có khả năng là một vấn đề.
Nếu tôi thêm các vị từ bổ sung mà tôi biết không thể là vấn đề, thì ước tính của tôi thực sự còn giảm hơn nữa - xuống còn 89,9 hàng.
chọn OrderDate, SalesOrderID từ Sales.SalesOrderHeader trong đó OrderDate> =convert (datetime, '20110601 00:00') tại múi giờ 'Giờ chuẩn miền Đông Hoa Kỳ' và OrderDate=convert (datetimeoffset, '20110601 00:00 +14:00') và OrderDate Ước tính quá nhiều hàng có nghĩa là quá nhiều bộ nhớ được phân bổ, nhưng ước tính quá ít có thể gây ra quá ít bộ nhớ, có khả năng cần một sự cố tràn để khắc phục sự cố (thường có thể là thảm họa từ góc độ hiệu suất). Hãy đọc bài đăng của Aaron để biết thêm thông tin về mức độ ảnh hưởng của ước tính kém.
Khi tôi xem xét cách xử lý việc hiển thị giá trị cho những người đó từ trước, tôi có thể sử dụng các truy vấn như sau:
WITH PeopleAndTZs AS (SELECT * FROM (VALUES ('Rob', 'Cen. Giờ chuẩn Úc'), ('Paul', 'Giờ chuẩn New Zealand'), ('Aaron', 'Giờ chuẩn miền Đông Hoa Kỳ') )) t (người, tz)) CHỌN tz. someone, o.SalesOrderID, o.OrderDate AT TIME ZONE 'UTC' AT TIME ZONE tz.tzFROM PeopleAndTZs tzCROSS THAM GIA Bán hàng.SalesOrderHeader oWHERE o.SalesOrderID GIỮA 44001 VÀ 44010;Và nhận kế hoạch này:
… Mà không có mối quan tâm như vậy - Scalar tính toán ở ngoài cùng bên phải đang chuyển đổi datetime OrderDate thành datetimeoffset cho UTC và Scalar tính toán ở ngoài cùng bên trái đang chuyển đổi nó thành múi giờ thích hợp cho người đó. Cảnh báo là do tôi đang thực hiện CROSS JOIN và đó hoàn toàn là do cố ý.
Ưu điểm và Nhược điểm của các phương pháp chuyển đổi thời gian khác
Trước AT TIME ZONE, một trong những tính năng yêu thích của tôi, nhưng thường không được đánh giá cao, của SQL 2008 là kiểu dữ liệu datetimeoffset. Điều này cho phép dữ liệu ngày / giờ cũng được lưu trữ với múi giờ, chẳng hạn như '20160101 00:00 +10:30', đó là thời điểm chúng tôi tổ chức Năm mới ở Adelaide năm nay. Để xem thời điểm đó ở Miền Đông Hoa Kỳ, tôi có thể sử dụng hàm SWITCHOFFSET.
SELECT SWITCHOFFSET ('20160101 00:00 +10:30', '-05:00'); - 2015-12-31 08:30:00.0000000 -05:00Đây là cùng một thời điểm trong thời gian, nhưng ở một nơi khác của thế giới. Nếu tôi đang nói chuyện điện thoại với ai đó ở Bắc Carolina hoặc New York, chúc họ Năm mới vui vẻ vì ở Adelaide đã quá nửa đêm, họ sẽ nói “Ý bạn là gì? Ở đây vẫn là giờ ăn sáng vào đêm giao thừa! ”
Vấn đề là để làm được điều này, tôi cần biết rằng vào tháng 1, Adelaide là +10:30 và miền Đông Hoa Kỳ là –5:00. Và đó thường là một nỗi đau. Đặc biệt nếu tôi đang hỏi về cuối tháng 3, đầu tháng 4, tháng 10, đầu tháng 11 - những thời điểm trong năm khi mọi người không thể chắc chắn người dân ở các quốc gia khác đang ở múi giờ nào vì họ thay đổi một giờ để tiết kiệm ánh sáng ban ngày và họ tất cả đều làm như vậy theo các quy tắc khác nhau. Máy tính của tôi cho tôi biết mọi người hiện đang ở múi giờ nào, nhưng khó hơn nhiều để biết họ sẽ ở múi giờ nào vào các thời điểm khác trong năm.
Để biết một số thông tin khác về việc chuyển đổi giữa các múi giờ và cách những người như Aaron xử lý việc tiết kiệm ánh sáng ban ngày, hãy xem các liên kết sau:
- Sử dụng AT TIME ZONE để sửa một báo cáo cũ (đó là tôi!)
- Xử lý chuyển đổi giữa các múi giờ trong SQL Server - phần 1
- Xử lý chuyển đổi giữa các múi giờ trong SQL Server - phần 2
- Xử lý chuyển đổi giữa các múi giờ trong SQL Server - phần 3
Và một số tài liệu chính thức của Microsoft:
- AT TIME ZONE (Transact-SQL)
- sys.time_zone_info (Transact-SQL)
- Trợ giúp và hỗ trợ về tiết kiệm ánh sáng ban ngày
Bạn có nên sử dụng AT TIME ZONE không?
AT TIME ZONE không hoàn hảo. Nhưng nó thực sự hữu ích - vô cùng hữu ích. Nó đủ linh hoạt để chấp nhận các cột và biến làm đầu vào và tôi có thể thấy rất nhiều tiềm năng cho nó. Nhưng nếu điều đó khiến ước tính của tôi bị lệch, thì tôi sẽ cần phải cẩn thận. Đối với mục đích hiển thị, điều này hoàn toàn không quan trọng và đó là nơi tôi có thể thấy nó hữu ích nhất. Việc chuyển đổi giá trị hiển thị sang hoặc từ UTC (hoặc đến hoặc từ giờ địa phương) dễ dàng hơn mà không cần ai phải vắt óc suy nghĩ về hiệu số và DST, là một chiến thắng lớn.
Đây thực sự là một trong những tính năng yêu thích của tôi trên SQL Server 2016. Tôi đã khóc vì một thứ như thế này trong một thời gian dài.
Ồ, và hầu hết tỷ người ở múi giờ nửa giờ đó đều ở Ấn Độ. Nhưng có thể bạn đã biết điều đó…