Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Menggunakan AT TIME ZONE untuk memperbaiki laporan lama

Segera setelah saya melihat fitur SQL 2016 AT TIME ZONE, yang saya tulis di sini di sqlperformance.com a beberapa bulan yang lalu, saya ingat sebuah laporan yang membutuhkan fitur ini. Posting ini membentuk studi kasus tentang bagaimana saya melihatnya berhasil, yang cocok dengan T-SQL Selasa bulan ini yang diselenggarakan oleh Matt Gordon (@sqlatspeed). (Ini hari Selasa T-SQL ke-87, dan saya benar-benar perlu menulis lebih banyak posting blog, terutama tentang hal-hal yang tidak diminta oleh T-SQL Selasa.)

Situasinya adalah ini, dan ini mungkin terdengar asing jika Anda membaca posting saya sebelumnya.

Jauh sebelum Solusi LobsterPot ada, saya perlu membuat laporan tentang insiden yang terjadi, dan khususnya, menunjukkan berapa kali respons dibuat dalam SLA dan berapa kali SLA terlewatkan. Misalnya, insiden Sev2 yang terjadi pada pukul 16:30 pada hari kerja harus mendapat tanggapan dalam waktu 1 jam, sedangkan insiden Sev2 yang terjadi pada pukul 17:30 pada hari kerja harus mendapat tanggapan dalam waktu 3 jam. Atau sesuatu seperti itu – saya lupa nomor yang terlibat, tetapi saya ingat bahwa karyawan helpdesk akan bernapas lega ketika jam 5 sore akan berputar, karena mereka tidak perlu menanggapi hal-hal dengan begitu cepat. Peringatan Sev1 15 menit tiba-tiba akan diperpanjang menjadi satu jam, dan urgensinya akan hilang.

Tapi masalah akan datang setiap kali waktu musim panas dimulai atau berakhir.

Saya yakin jika Anda pernah berurusan dengan database, Anda akan tahu betapa menyakitkannya waktu musim panas. Seharusnya Ben Franklin datang dengan ide - dan untuk itu dia harus disambar petir atau sesuatu. Australia Barat mencobanya selama beberapa tahun baru-baru ini, dan dengan bijaksana meninggalkannya. Dan konsensus umum adalah menyimpan data tanggal/waktu adalah melakukannya di UTC.

Jika Anda tidak menyimpan data dalam UTC, Anda berisiko mengalami acara yang dimulai pada pukul 02:45 dan berakhir pada pukul 02:15 setelah waktu berjalan kembali. Atau mengalami insiden SLA yang dimulai pada 01:59 tepat sebelum waktu berjalan. Sekarang, waktu ini baik-baik saja jika Anda menyimpan zona waktu tempat mereka berada, tetapi dalam waktu UTC hanya berfungsi seperti yang diharapkan.

…kecuali untuk pelaporan.

Karena bagaimana saya bisa tahu apakah tanggal tertentu sebelum musim panas dimulai atau sesudahnya? Saya mungkin tahu bahwa sebuah insiden terjadi pada pukul 06:30 di UTC, tetapi apakah itu pukul 16:30 di Melbourne atau 17:30? Jelas saya dapat mempertimbangkan bulan apa itu, karena saya tahu bahwa Melbourne mengamati waktu musim panas dari hari Minggu pertama di bulan Oktober hingga hari Minggu pertama di bulan April, tetapi kemudian jika ada pelanggan di Brisbane, dan Auckland, dan Los Angeles, dan Phoenix, dan berbagai tempat di Indiana, segalanya menjadi lebih rumit.

Untuk menyiasatinya, ada sangat sedikit zona waktu di mana SLA dapat ditentukan untuk perusahaan itu. Itu hanya dianggap terlalu sulit untuk memenuhi lebih dari itu. Sebuah laporan kemudian dapat disesuaikan untuk mengatakan "Pertimbangkan bahwa pada tanggal tertentu zona waktu berubah dari X ke Y". Rasanya berantakan, tapi berhasil. Tidak perlu apa pun untuk mencari registri Windows, dan pada dasarnya itu hanya berfungsi.

Tapi hari ini, saya akan melakukannya secara berbeda.

Sekarang, saya akan menggunakan AT TIME ZONE.

Soalnya, sekarang saya bisa menyimpan informasi zona waktu pelanggan sebagai milik pelanggan. Saya kemudian dapat menyimpan setiap waktu kejadian dalam UTC, memungkinkan saya untuk melakukan perhitungan yang diperlukan seputar jumlah menit untuk merespons, menyelesaikan, dan seterusnya, sambil dapat melaporkan menggunakan waktu lokal pelanggan. Dengan asumsi IncidentTime saya sebenarnya telah disimpan menggunakan datetime, daripada datetimeoffset, itu hanya masalah menggunakan kode seperti:

i.IncidentTime AT TIME ZONE 'UTC' AT TIME ZONE c.tz

…yang pertama-tama menempatkan i.IncidentTime tanpa zona waktu ke dalam UTC, sebelum mengonversinya ke zona waktu pelanggan. Dan zona waktu ini dapat berupa 'Waktu Standar Timur AUS', atau 'Waktu Standar Mauritius', atau apa pun. Dan SQL Engine dibiarkan mencari tahu offset apa yang digunakan untuk itu.

Pada titik ini, saya dapat dengan mudah membuat laporan yang mencantumkan setiap insiden di seluruh periode waktu, dan menunjukkannya di zona waktu lokal pelanggan. Saya dapat mengonversi nilai ke tipe data waktu, dan kemudian melaporkan jumlah insiden dalam jam kerja atau tidak.

Dan semua ini sangat berguna, tetapi bagaimana dengan pengindeksan untuk menangani ini dengan baik? Bagaimanapun, AT TIME ZONE adalah sebuah fungsi. Tetapi mengubah zona waktu tidak mengubah urutan insiden yang sebenarnya terjadi, jadi seharusnya tidak apa-apa.

Untuk menguji ini, saya membuat tabel bernama dbo.Incidens, dan mengindeks kolom IncidentTime. Kemudian saya menjalankan kueri ini, dan mengonfirmasi bahwa pencarian indeks telah digunakan.

select i.IncidentTime, itz.LocalTime
from dbo.Incidents i
cross apply (select i.IncidentTime AT TIME ZONE 'UTC' 
  AT TIME ZONE 'Cen. Australia Standard Time') itz (LocalTime)
where i.IncidentTime >= '20170201'
and i.IncidentTime < '20170301';

Tapi saya ingin memfilter di itz.LocalTime…

select i.IncidentTime, itz.LocalTime
from dbo.Incidents i
cross apply (select i.IncidentTime AT TIME ZONE 'UTC' 
  AT TIME ZONE 'Cen. Australia Standard Time') itz (LocalTime)
where itz.LocalTime >= '20170201'
and itz.LocalTime < '20170301';

Tidak beruntung. Itu tidak seperti indeks.

Peringatan itu karena harus melihat lebih banyak daripada data yang saya minati.

Saya bahkan mencoba menggunakan tabel dengan bidang datetimeoffset. Lagi pula, AT TIME ZONE dapat mengubah urutan saat berpindah dari datetime ke datetimeoffset, meskipun urutannya tidak berubah saat berpindah dari datetimeoffset ke datetimeoffset lainnya. Saya bahkan mencoba memastikan bahwa benda yang saya bandingkan berada di zona waktu.

select i.IncidentTime, itz.LocalTime
from dbo.IncidentsOffset i
cross apply (select i.IncidentTime AT TIME ZONE 'Cen. Australia Standard Time') itz (LocalTime)
where itz.LocalTime >= cast('20170201' as datetimeoffset) 
  AT TIME ZONE 'Cen. Australia Standard Time'
and itz.LocalTime < cast('20170301' as datetimeoffset) 
  AT TIME ZONE 'Cen. Australia Standard Time';

Masih belum beruntung!

Jadi sekarang saya punya dua pilihan. Salah satunya adalah menyimpan versi yang dikonversi bersama versi UTC, dan mengindeksnya. Saya pikir itu menyakitkan. Ini tentu saja lebih banyak perubahan basis data daripada yang saya inginkan.

Pilihan lainnya adalah menggunakan apa yang saya sebut predikat pembantu. Ini adalah jenis hal yang Anda lihat ketika Anda menggunakan LIKE. Itu adalah predikat yang dapat digunakan sebagai Predikat Seek, tetapi tidak persis seperti yang Anda minta.

Saya pikir tidak peduli zona waktu apa yang saya minati, IncidentTimes yang saya pedulikan berada dalam rentang yang sangat spesifik. Kisaran itu tidak lebih dari satu hari lebih besar dari kisaran pilihan saya, di kedua sisi.

Jadi saya akan menyertakan dua predikat tambahan.

select i.IncidentTime, itz.LocalTime
from dbo.IncidentsOffset i
cross apply (select i.IncidentTime 
    AT TIME ZONE 'Cen. Australia Standard Time') itz (LocalTime)
where itz.LocalTime >= cast('20170201' as datetimeoffset) 
  AT TIME ZONE 'Cen. Australia Standard Time'
and itz.LocalTime < cast('20170301' as datetimeoffset) 
  AT TIME ZONE 'Cen. Australia Standard Time
and i.IncidentTime >= dateadd(day,-1,'20170201')
and i.IncidentTime < dateadd(day, 1,'20170301');

Sekarang, indeks saya dapat digunakan. Itu harus melihat melalui 30 baris sebelum memfilternya ke 28 yang penting – tapi itu jauh lebih baik daripada memindai semuanya.

Dan Anda tahu – ini adalah jenis perilaku yang saya lihat sepanjang waktu dari kueri biasa, seperti ketika saya melakukan CAST(myDateTimeColumns AS DATE) =@SomeDate, atau menggunakan LIKE.

Saya baik-baik saja dengan ini. AT TIME ZONE sangat bagus untuk memungkinkan saya menangani konversi zona waktu saya, dan dengan mempertimbangkan apa yang terjadi dengan kueri saya, saya juga tidak perlu mengorbankan kinerja.

@rob_farley


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Beberapa masalah kecil dengan sampel Hekaton

  2. Tingkat Isolasi SNAPSHOT

  3. Kunci Utama Dalam SQL:Semua yang Perlu Anda Ketahui Tentang Operasi Kunci Utama

  4. Temukan Kolom yang Dikembalikan oleh Fungsi Bernilai Tabel (Contoh T-SQL)

  5. Prisma, cara membalik urutan