การออกแบบคลังข้อมูลสำหรับการรายงานข้อมูลกับเขตเวลาต่างๆ


10

เรากำลังพยายามปรับการออกแบบคลังข้อมูลให้เหมาะสมซึ่งจะสนับสนุนการรายงานข้อมูลสำหรับเขตเวลาต่างๆ ตัวอย่างเช่นเราอาจมีรายงานมูลค่ากิจกรรมหนึ่งเดือน (หลายล้านแถว) ที่ต้องแสดงกิจกรรมที่จัดกลุ่มตามชั่วโมงของวัน และแน่นอนว่าชั่วโมงของวันนั้นจะต้องเป็นชั่วโมง "ท้องถิ่น" สำหรับเขตเวลาที่กำหนด

เรามีการออกแบบที่ทำงานได้ดีเมื่อเราเพิ่งสนับสนุน UTC และเวลาท้องถิ่น การออกแบบมาตรฐานของมิติวันที่และเวลาสำหรับ UTC และเวลาท้องถิ่นรหัสของบนตารางข้อมูลจริง อย่างไรก็ตามวิธีการดังกล่าวดูเหมือนจะไม่ขยายหากเราต้องสนับสนุนการรายงานสำหรับเขตเวลา 100+

ตารางความจริงของเรากว้างขึ้นมาก นอกจากนี้เราจะต้องแก้ปัญหาไวยากรณ์ใน SQL เพื่อระบุวันที่และเวลาที่จะใช้สำหรับการจัดกลุ่มในการเรียกใช้รายงานใด ๆ อาจเป็นคำสั่งกรณีที่มีขนาดใหญ่มาก?

ฉันเห็นคำแนะนำเพื่อรับข้อมูลทั้งหมดตามช่วงเวลา UTC ที่คุณครอบคลุมจากนั้นส่งคืนไปยังเลเยอร์การนำเสนอเพื่อแปลงเป็นแบบโลคัลและรวมที่นั่น แต่การทดสอบที่ จำกัด กับ SSRS ชี้ให้เห็นว่าจะช้ามาก

ฉันได้อ่านหนังสือบางเล่มเกี่ยวกับเรื่องนี้ด้วยและพวกเขาทั้งหมดพูดว่ามีเพียง UTC และแปลงเป็นไฟล์แสดงหรือมี UTC และหนึ่งในท้องถิ่น จะขอบคุณความคิดและข้อเสนอแนะใด ๆ

หมายเหตุ: คำถามนี้คล้ายกับ: การจัดการโซนเวลาใน data mart / warehouseแต่ฉันไม่สามารถแสดงความคิดเห็นกับคำถามนั้นได้ดังนั้นรู้สึกว่าสมควรได้รับคำถามของตัวเอง

อัปเดต:ฉันเลือกคำตอบของแอรอนหลังจากเขาทำการอัปเดตที่สำคัญและโพสต์โค้ดตัวอย่างและไดอะแกรม ความคิดเห็นก่อนหน้าของฉันเกี่ยวกับคำตอบของเขาจะไม่สมเหตุสมผลอีกต่อไปเนื่องจากพวกเขาอ้างถึงการแก้ไขคำตอบเดิม ฉันจะพยายามกลับมาและอัปเดตสิ่งนี้อีกครั้งหากรับประกัน


ในบริบทของคำตอบของฉัน (และการอัปเดตที่ฉันจะโพสต์ไว้ในภายหลัง) ข้อมูลของคุณจะไปได้ไกลแค่ไหน? รายงานประจำเดือนแสดง 28-31 ชุดตลอด 24 ชั่วโมงหรือไม่ มันจะเป็น "เดือนในปฏิทิน" เสมอหรือเป็นช่วงใด ๆ ก็ได้จริงหรือ สิ่งที่ควรแสดงเมื่อหนึ่งในวันที่คือวันที่ DST ไปข้างหน้า / ย้อนกลับสปริงสำหรับเขตเวลาที่เลือก? นอกจากนี้อินพุตสำหรับรายงานคืออะไร คุณแปลงเวลาท้องถิ่นของผู้ใช้เป็น UTC โดยยึดตามตำแหน่งที่ตั้งปัจจุบันของพวกเขาโดยอัตโนมัติมีการตั้งค่าหรือไม่พวกเขาเลือกด้วยตนเองหรือคุณอนุมานด้วยวิธีอื่นหรือคุณต้องการให้คิวรีค้นหาหรือไม่
Aaron Bertrand

เพื่อตอบคำถามของคุณ: ข้อมูลอาจย้อนกลับไปถึง 2 ปี เรามีรายงานบางส่วนที่แสดงชุดข้อมูล 24 ชั่วโมงเพียงชุดเดียวและรายงานอื่น ๆ ที่มีช่วงเวลา 24 ชั่วโมงต่อวันในช่วงวันที่ของรายงาน ช่วงวันที่สามารถเป็นอะไรก็ได้ที่ผู้ใช้ต้องการ ผู้ใช้เลือกวันที่เริ่มต้นและสิ้นสุด (และเวลา) จากนั้นเลือกเขตเวลาที่ต้องการจากดรอปดาวน์
Peter M

อาจเป็นไปได้ซ้ำกับการจัดการโซนเวลาใน data mart / warehouse
Jon of All Trades

คำตอบ:


18

ฉันได้แก้ไขปัญหานี้แล้วโดยการมีตารางปฏิทินที่ง่ายมาก - ในแต่ละปีจะมีหนึ่งแถวต่อเขตเวลาที่สนับสนุนโดยมีออฟเซ็ตมาตรฐานและช่วงเวลาเริ่มต้นและวันที่สิ้นสุดของ DST และออฟเซ็ต (ถ้าเขตเวลานั้นรองรับ) จากนั้นฟังก์ชั่นที่มีมูลค่าเป็นตารางแบบอินไลน์ฟังก์ชันที่มีค่าเป็นตารางซึ่งต้องใช้เวลาแหล่งที่มา (ใน UTC แน่นอน) และเพิ่ม / ลบออฟเซ็ต

เห็นได้ชัดว่าสิ่งนี้จะไม่ทำงานได้ดีมากหากคุณรายงานข้อมูลส่วนใหญ่ การแบ่งพาร์ติชันอาจช่วยได้ แต่คุณยังคงมีกรณีที่สองสามชั่วโมงสุดท้ายในหนึ่งปีหรือสองสามชั่วโมงแรกในปีถัดไปเป็นจริงของปีที่แตกต่างกันเมื่อแปลงเป็นเขตเวลาที่เฉพาะเจาะจง - ดังนั้นคุณจึงไม่เคยได้รับพาร์ติชันที่แท้จริง การแยกยกเว้นเมื่อช่วงการรายงานของคุณไม่รวมวันที่ 31 ธันวาคมหรือ 1 มกราคม

มีสองสามกรณีขอบแปลก ๆ ที่คุณต้องพิจารณา:

  • 2014-11-02 05:30 UTC และ 2014-11-02 06:30 UTC ทั้งคู่เปลี่ยนเป็น 01:30 น. ในเขตเวลาตะวันออกตัวอย่างเช่น (ครั้งแรกเป็นครั้งแรกที่ 01:30 ถูกชนในพื้นที่จากนั้นหนึ่งครั้ง เป็นครั้งที่สองเมื่อนาฬิกาย้อนกลับจาก 2:00 น. ถึง 1:00 น. และผ่านไปอีกครึ่งชั่วโมง) ดังนั้นคุณต้องตัดสินใจว่าจะจัดการกับชั่วโมงของการรายงานได้อย่างไรตาม UTC คุณควรเห็นปริมาณการใช้งานหรือปริมาณของสิ่งที่คุณวัดเป็นสองเท่าเมื่อสองชั่วโมงนั้นถูกแมปกับหนึ่งชั่วโมงในเขตเวลาที่สังเกต DST สิ่งนี้สามารถเล่นเกมสนุก ๆ ที่มีการจัดลำดับเหตุการณ์เนื่องจากบางสิ่งที่ต้องเกิดขึ้นอย่างมีเหตุมีผลหลังจากที่บางอย่างปรากฏขึ้นที่จะเกิดขึ้นก่อนหน้านี้เมื่อเวลาถูกปรับเป็นชั่วโมงเดียวแทนสอง ตัวอย่างสุดขั้วคือการดูหน้าเว็บที่เกิดขึ้นในเวลา 05:59 UTC จากนั้นคลิกที่เกิดขึ้นเวลา 06:00 UTC ในเวลา UTC สิ่งเหล่านี้เกิดขึ้นหนึ่งนาที แต่เมื่อแปลงเป็นเวลาตะวันออกมุมมองเกิดขึ้นเวลา 1:59 น. และการคลิกเกิดขึ้นหนึ่งชั่วโมงก่อนหน้านี้

  • 2014-03-09 02:30 ไม่เคยเกิดขึ้นในสหรัฐอเมริกา นี่เป็นเพราะเวลา 2:00 น. เราจะหมุนนาฬิกาไปข้างหน้าจนถึง 3:00 น มีโอกาสมากที่คุณจะต้องการแจ้งข้อผิดพลาดหากผู้ใช้ป้อนเวลาดังกล่าวและขอให้คุณแปลงเป็น UTC หรือออกแบบฟอร์มของคุณเพื่อให้ผู้ใช้ไม่สามารถเลือกเวลาดังกล่าวได้

แม้ว่าในกรณีเหล่านั้นในใจฉันยังคิดว่าคุณมีวิธีการที่ถูกต้อง: เก็บข้อมูลใน UTC การแมปข้อมูลไปยังโซนเวลาอื่น ๆ จาก UTC ได้ง่ายกว่าจากบางโซนเวลาไปยังโซนเวลาอื่นโดยเฉพาะอย่างยิ่งเมื่อเขตเวลาเริ่มต้น / สิ้นสุด DST แตกต่างกันในวันที่ที่แตกต่างกันและแม้แต่เขตเวลาเดียวกันสามารถสลับการใช้กฎที่แตกต่างกัน เช่นสหรัฐอเมริกาเปลี่ยนกฎ 6 ปีก่อนหรือมากกว่านั้น)

คุณจะต้องการใช้ตารางปฏิทินสำหรับสิ่งเหล่านี้ไม่ใช่CASE นิพจน์ที่ใหญ่โต(ไม่ใช่คำสั่ง ) ฉันเพิ่งเขียนชุดสามส่วนสำหรับMSSQLTips.comเกี่ยวกับเรื่องนี้; ฉันคิดว่าส่วนที่ 3 จะมีประโยชน์มากที่สุดสำหรับคุณ:

http://www.mssqltips.com/sqlservertip/3173/handle-conversion-between-time-zones-in-sql-server--part-1/

http://www.mssqltips.com/sqlservertip/3174/handle-conversion-between-time-zones-in-sql-server--part-2/

http://www.mssqltips.com/sqlservertip/3175/handle-conversion-between-time-zones-in-sql-server--part-3/


ตัวอย่างจริงในขณะเดียวกัน

สมมติว่าคุณมีตารางความจริงง่ายๆ ข้อเท็จจริงเดียวที่ฉันสนใจในกรณีนี้คือเวลาของเหตุการณ์ แต่ฉันจะเพิ่ม GUID ที่ไม่มีความหมายเพียงเพื่อทำให้ตารางกว้างพอที่จะสนใจ อีกครั้งเพื่อให้ชัดเจนตารางข้อเท็จจริงเก็บเหตุการณ์ในเวลา UTC และเวลา UTC เท่านั้น ฉันได้ต่อท้ายคอลัมน์ด้วย_UTCดังนั้นจึงไม่มีความสับสน

CREATE TABLE dbo.Fact
(
  EventTime_UTC DATETIME NOT NULL,
  Filler UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID()
);
GO

CREATE CLUSTERED INDEX x ON dbo.Fact(EventTime_UTC);
GO

ตอนนี้เรามาโหลดตารางข้อเท็จจริงของเรากับ 10,000,000 แถว - แทนทุก 3 วินาที (1,200 แถวต่อชั่วโมง) จาก 2013-12-30 เวลาเที่ยงคืน UTC จนกระทั่งบางครั้งหลังจาก 5:00 UTC ใน 2014-12-12 สิ่งนี้ช่วยให้มั่นใจได้ว่าข้อมูลจะเลาะเลียบไปตามขอบเขตปีเช่นเดียวกับ DST ไปข้างหน้าและย้อนกลับสำหรับเขตเวลาหลายเขต มันดูน่ากลัวจริงๆ แต่ใช้เวลาประมาณ 9 วินาทีในระบบของฉัน ตารางควรอยู่ที่ประมาณ 325 MB

;WITH x(c) AS 
(
  SELECT TOP (10000000) DATEADD(SECOND, 
    3*(ROW_NUMBER() OVER (ORDER BY s1.[object_id])-1),
    '20131230')
  FROM sys.all_columns AS s1
  CROSS JOIN sys.all_columns AS s2
  ORDER BY s1.[object_id]
)
INSERT dbo.Fact WITH (TABLOCKX) (EventTime_UTC) 
  SELECT c FROM x;

และเพื่อแสดงให้เห็นว่าเคียวรีค้นหาทั่วไปจะมีลักษณะเป็นอย่างไรกับตารางแถว 10 มม. นี้หากฉันเรียกใช้คิวรีนี้:

SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, EventTime_UTC), 0),
  COUNT(*)
FROM dbo.Fact 
WHERE EventTime_UTC >= '20140308'
AND EventTime_UTC < '20140311'
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, EventTime_UTC), 0);

ฉันได้รับแผนนี้และผลตอบแทนเป็น 25 มิลลิวินาที * อ่าน 358 ครั้งเพื่อส่งคืนผลรวม 72 ชั่วโมง:

ป้อนคำอธิบายรูปภาพที่นี่

* ระยะเวลาที่วัดโดยSQL Sentry Plan Explorerฟรีของเราซึ่งไม่ใช้ผลลัพธ์ดังนั้นนี่จึงไม่รวมเวลาการถ่ายโอนข้อมูลเครือข่ายของการเรนเดอร์ ฯลฯ เป็นข้อจำกัดความรับผิดชอบเพิ่มเติมฉันทำงานกับ SQL Sentry

เห็นได้ชัดว่าใช้เวลานานขึ้นเล็กน้อยถ้าฉันทำให้ช่วงของฉันใหญ่เกินไป - หนึ่งเดือนมีข้อมูล 258ms สองเดือนใช้เวลามากกว่า 500 มิลลิวินาทีและอื่น ๆ คู่ขนานอาจเตะใน:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือที่ที่คุณเริ่มคิดเกี่ยวกับวิธีการแก้ปัญหาอื่น ๆ ที่ดีกว่าเพื่อตอบสนองคำสั่งการรายงานและไม่มีอะไรเกี่ยวข้องกับเขตเวลาที่เอาต์พุตของคุณจะแสดง ฉันจะไม่เข้าไปในนั้นฉันแค่ต้องการแสดงให้เห็นว่าการแปลงเขตเวลาไม่ได้ทำให้แบบสอบถามการรายงานของคุณดูดมากขึ้นไปอีกและพวกเขาอาจดูดถ้าคุณได้รับช่วงขนาดใหญ่ที่ไม่ได้รับการสนับสนุนที่เหมาะสม ดัชนี ฉันจะใช้ช่วงวันที่ขนาดเล็กเพื่อแสดงว่าตรรกะนั้นถูกต้องและให้คุณกังวลเกี่ยวกับการทำให้แน่ใจว่าแบบสอบถามแบบรายงานตามช่วงของคุณทำงานได้อย่างเพียงพอโดยมีหรือไม่มีการแปลงเขตเวลา

โอเคตอนนี้เราต้องใช้ตารางเพื่อจัดเก็บเขตเวลาของเรา (ด้วยออฟเซ็ตในหน่วยนาทีเนื่องจากทุกคนไม่ได้ปิด UTC) และ DST เปลี่ยนวันที่ที่รองรับในแต่ละปี เพื่อความง่ายฉันจะป้อนเขตเวลาเพียงไม่กี่ปีและหนึ่งปีเพื่อจับคู่ข้อมูลด้านบน

CREATE TABLE dbo.TimeZones
(
  TimeZoneID TINYINT    NOT NULL PRIMARY KEY,
  Name       VARCHAR(9) NOT NULL,
  Offset     SMALLINT   NOT NULL, -- minutes
  DSTName    VARCHAR(9) NOT NULL,
  DSTOffset  SMALLINT   NOT NULL  -- minutes
);

รวมเขตเวลาสำหรับความหลากหลายด้วยบางส่วนมีออฟเซ็ตครึ่งชั่วโมงบางตัวไม่เห็น DST โปรดทราบว่าออสเตรเลียในซีกโลกใต้สังเกต DST ในช่วงฤดูหนาวของเราดังนั้นนาฬิกาของพวกเขาจะกลับไปในเดือนเมษายนและส่งต่อในเดือนตุลาคม (ตารางด้านบนพลิกชื่อ แต่ฉันไม่แน่ใจว่าจะทำให้โซนเวลาซีกโลกใต้สับสนน้อยลงได้อย่างไร)

INSERT dbo.TimeZones VALUES
(1, 'UTC',     0, 'UTC',     0),
(2, 'GMT',     0, 'BST',    60), 
     -- London = UTC in winter, +1 in summer
(3, 'EST',  -300, 'EDT',  -240), 
     -- East coast US (-5 h in winter, -4 in summer)
(4, 'ACDT',  630, 'ACST',  570), 
     -- Adelaide (Australia) +10.5 h Oct - Apr, +9.5 Apr - Oct
(5, 'ACST',  570, 'ACST',  570); 
     -- Darwin (Australia) +9.5 h year round

ทีนี้ตารางปฏิทินที่ต้องรู้เมื่อมีการเปลี่ยนแปลง TZ ฉันจะแทรกแถวของความสนใจ (แต่ละเขตเวลาด้านบนและเฉพาะการเปลี่ยนแปลงเวลาสำหรับปี 2014) เพื่อความสะดวกในการคำนวณกลับไปกลับมาฉันเก็บทั้งช่วงเวลาใน UTC ที่มีการเปลี่ยนแปลงเขตเวลาและช่วงเวลาเดียวกันในเวลาท้องถิ่น สำหรับเขตเวลาที่ไม่สังเกต DST เป็นมาตรฐานตลอดทั้งปีและ DST "เริ่มต้น" ในวันที่ 1 มกราคม

CREATE TABLE dbo.Calendar
(
  TimeZoneID    TINYINT NOT NULL FOREIGN KEY
                REFERENCES dbo.TimeZones(TimeZoneID),
  [Year]        SMALLDATETIME NOT NULL,
  UTCDSTStart   SMALLDATETIME NOT NULL,
  UTCDSTEnd     SMALLDATETIME NOT NULL,
  LocalDSTStart SMALLDATETIME NOT NULL,
  LocalDSTEnd   SMALLDATETIME NOT NULL,
  PRIMARY KEY (TimeZoneID, [Year])
);

คุณสามารถเติมสิ่งนี้ด้วยอัลกอริธึม (และชุดเคล็ดลับที่กำลังจะมาถึงใช้เทคนิคการตั้งค่าที่ฉลาดถ้าฉันบอกตัวเอง) แทนที่จะวนซ้ำเติมด้วยตนเองคุณมีอะไรบ้าง สำหรับคำตอบนี้ฉันตัดสินใจที่จะใส่ข้อมูลด้วยตนเองเป็นเวลาหนึ่งปีสำหรับเขตเวลาห้าโซนและฉันจะไม่ไปสนใจกลอุบายแฟนซีใด ๆ

INSERT dbo.Calendar VALUES
(1, '20140101', '20140101 00:00','20150101 00:00','20140101 00:00','20150101 00:00'),
(2, '20140101', '20140330 01:00','20141026 00:00','20140330 02:00','20141026 01:00'),
(3, '20140101', '20140309 07:00','20141102 06:00','20140309 03:00','20141102 01:00'),
(4, '20140101', '20140405 16:30','20141004 16:30','20140406 03:00','20141005 02:00'),
(5, '20140101', '20140101 00:00','20150101 00:00','20140101 00:00','20150101 00:00');

โอเคเรามีข้อมูลข้อเท็จจริงของเราและตาราง "มิติ" ของเรา (ฉันประจบประแจงเมื่อฉันพูดอย่างนั้น) แล้วตรรกะคืออะไร ฉันคิดว่าคุณจะต้องให้ผู้ใช้เลือกเขตเวลาและป้อนช่วงวันที่ของแบบสอบถาม ฉันจะสมมติว่าช่วงวันที่จะเป็นวันเต็มในเขตเวลาของตนเอง ไม่มีวันบางส่วนไม่ต้องสนใจชั่วโมงบางส่วน ดังนั้นพวกเขาจะผ่านในวันที่เริ่มต้นวันที่สิ้นสุดและ TimeZoneID จากนั้นเราจะใช้ฟังก์ชันสเกลาร์เพื่อแปลงวันที่เริ่มต้น / สิ้นสุดจากเขตเวลานั้นเป็น UTC ซึ่งจะช่วยให้เราสามารถกรองข้อมูลตามช่วง UTC เมื่อเราดำเนินการแล้วและทำการรวมกับมันแล้วเราสามารถนำการแปลงของเวลาที่จัดกลุ่มกลับไปยังโซนเวลาต้นทางก่อนที่จะแสดงต่อผู้ใช้

สเกลาร์ UDF:

CREATE FUNCTION dbo.ConvertToUTC
(
  @Source   SMALLDATETIME,
  @SourceTZ TINYINT
)
RETURNS SMALLDATETIME
WITH SCHEMABINDING
AS
BEGIN
  RETURN 
  (
    SELECT DATEADD(MINUTE, -CASE 
        WHEN @Source >= src.LocalDSTStart 
         AND @Source < src.LocalDSTEnd THEN t.DSTOffset 
        WHEN @Source >= DATEADD(HOUR,-1,src.LocalDSTStart) 
         AND @Source < src.LocalDSTStart THEN NULL
        ELSE t.Offset END, @Source)
    FROM dbo.Calendar AS src
    INNER JOIN dbo.TimeZones AS t 
    ON src.TimeZoneID = t.TimeZoneID
    WHERE src.TimeZoneID = @SourceTZ 
      AND t.TimeZoneID = @SourceTZ
      AND DATEADD(MINUTE,t.Offset,@Source) >= src.[Year]
      AND DATEADD(MINUTE,t.Offset,@Source) < DATEADD(YEAR, 1, src.[Year])
  );
END
GO

และฟังก์ชั่นที่มีค่าเป็นตาราง:

CREATE FUNCTION dbo.ConvertFromUTC
(
  @Source   SMALLDATETIME,
  @SourceTZ TINYINT
)
RETURNS TABLE
WITH SCHEMABINDING
AS
 RETURN 
 (
  SELECT 
     [Target] = DATEADD(MINUTE, CASE 
       WHEN @Source >= trg.UTCDSTStart 
        AND @Source < trg.UTCDSTEnd THEN tz.DSTOffset 
       ELSE tz.Offset END, @Source)
  FROM dbo.Calendar AS trg
  INNER JOIN dbo.TimeZones AS tz
  ON trg.TimeZoneID = tz.TimeZoneID
  WHERE trg.TimeZoneID = @SourceTZ 
  AND tz.TimeZoneID = @SourceTZ
  AND @Source >= trg.[Year] 
  AND @Source < DATEADD(YEAR, 1, trg.[Year])
);

และกระบวนการที่ใช้ ( แก้ไข : อัปเดตเพื่อจัดการการจัดกลุ่มออฟเซ็ต 30 นาที):

CREATE PROCEDURE dbo.ReportOnDateRange
  @Start      SMALLDATETIME, -- whole dates only please! 
  @End        SMALLDATETIME, -- whole dates only please!
  @TimeZoneID TINYINT
AS 
BEGIN
  SET NOCOUNT ON;

  SELECT @Start = dbo.ConvertToUTC(@Start, @TimeZoneID),
         @End   = dbo.ConvertToUTC(@End,   @TimeZoneID);

  ;WITH x(t,c) AS
  (
    SELECT DATEDIFF(MINUTE, @Start, EventTime_UTC)/60, 
      COUNT(*) 
    FROM dbo.Fact 
    WHERE EventTime_UTC >= @Start
      AND EventTime_UTC <  DATEADD(DAY, 1, @End)
    GROUP BY DATEDIFF(MINUTE, @Start, EventTime_UTC)/60
  )
  SELECT 
    UTC = DATEADD(MINUTE, x.t*60, @Start), 
    [Local] = y.[Target], 
    [RowCount] = x.c 
  FROM x OUTER APPLY 
    dbo.ConvertFromUTC(DATEADD(MINUTE, x.t*60, @Start), @TimeZoneID) AS y
  ORDER BY UTC;
END
GO

(คุณอาจต้องการไปที่ลัดวงจรที่นั่นหรือขั้นตอนการจัดเก็บแยกต่างหากในกรณีที่ผู้ใช้ต้องการรายงานใน UTC - การแปลไปและกลับจาก UTC เป็นงานที่ยุ่งมากอย่างเห็นได้ชัด)

ตัวอย่างการโทร:

EXEC dbo.ReportOnDateRange 
  @Start      = '20140308', 
  @End        = '20140311', 
  @TimeZoneID = 3;

ส่งคืนใน 41ms * และสร้างแผนนี้:

ป้อนคำอธิบายรูปภาพที่นี่

* อีกครั้งพร้อมผลลัพธ์ที่ถูกทิ้ง

สำหรับ 2 เดือนจะส่งคืนใน 507ms และแผนเหมือนกันนอกเหนือจาก rowcounts:

ป้อนคำอธิบายรูปภาพที่นี่

ในขณะที่มีความซับซ้อนมากขึ้นเล็กน้อยและใช้เวลาเพิ่มขึ้นเล็กน้อยฉันค่อนข้างมั่นใจว่าวิธีการแบบนี้จะทำงานได้ดีกว่าวิธีการเชื่อมโยงตาราง และนี่เป็นตัวอย่างข้อมือปิดสำหรับคำตอบ dba.se; ฉันแน่ใจว่าตรรกะและประสิทธิภาพของฉันสามารถปรับปรุงได้โดยคนฉลาดกว่าฉันมาก

คุณสามารถอ่านข้อมูลเพื่อดูกรณีขอบที่ฉันพูดถึง - ไม่มีแถวเอาท์พุทสำหรับชั่วโมงที่นาฬิกาหมุนไปข้างหน้าสองแถวสำหรับชั่วโมงที่พวกเขาย้อนกลับ (และชั่วโมงนั้นเกิดขึ้นสองครั้ง) นอกจากนี้คุณยังสามารถเล่นกับค่าที่ไม่ดี; ถ้าคุณผ่านในปี 20140309 02:30 เวลาฝั่งตะวันออกมันจะไม่ทำงานได้ดีเกินไป

ฉันอาจไม่มีสมมติฐานทั้งหมดที่ถูกต้องเกี่ยวกับวิธีการรายงานของคุณจะทำงานดังนั้นคุณอาจต้องทำการปรับเปลี่ยนบางอย่าง แต่ฉันคิดว่านี่ครอบคลุมพื้นฐาน


0

คุณสามารถทำการแปลงใน proc ที่เก็บไว้หรือมุมมองที่กำหนดพารามิเตอร์แทนเลเยอร์การนำเสนอได้หรือไม่? อีกทางเลือกหนึ่งคือการสร้างลูกบาศก์และมีการคำนวณเป็นลูกบาศก์

คำอธิบายจากความคิดเห็น:

OP พบปัญหาด้านประสิทธิภาพด้วยการทดสอบที่ จำกัด ของเขาโดยทำการคำนวณในเลเยอร์การนำเสนอ ข้อเสนอแนะของฉันคือการย้ายไปยังฐานข้อมูล ใน sql คุณสามารถทำมุมมองที่กำหนดพารามิเตอร์โดยใช้ฟังก์ชันที่มีค่าของตาราง ขึ้นอยู่กับเขตเวลาที่ส่งผ่านไปยังฟังก์ชันนี้ข้อมูลสามารถคำนวณและส่งคืนจากตาราง UTC หวังว่านี่จะทำให้คำตอบดั้งเดิมของฉันชัดเจนขึ้น


ดังนั้นมุมมองที่มี 100 คอลัมน์เพิ่มเติมซึ่งแต่ละแถวมีเวลาแหล่งที่มาใน UTC แปลเป็นโซนเวลา 100+ ทั้งหมดหรือไม่ ฉันไม่สามารถเข้าใจได้แม้กระทั่งว่ามุมมองดังกล่าวจะถูกเขียนขึ้นอย่างไร นอกจากนี้โปรดสังเกตว่า SQL Server ไม่มี "มุมมองแบบกำหนดพารามิเตอร์" ...
Aaron Bertrand

อืม .. นั่นคือสิ่งที่คุณคิด และนั่นไม่ใช่สิ่งที่ฉันหมายถึง
KNI

1
ดังนั้นทำให้ฉันคิดอย่างอื่น ฉันไม่ได้ลงคะแนนเพียงแค่พยายามที่จะส่งเสริมความชัดเจนในคำตอบของคุณ
Aaron Bertrand

op พบปัญหาด้านประสิทธิภาพด้วยการทดสอบที่ จำกัด ของเขาโดยทำการคำนวณในเลเยอร์การนำเสนอ ข้อเสนอแนะของฉันคือการย้ายไปยังฐานข้อมูล ใน sql คุณสามารถทำมุมมองที่กำหนดพารามิเตอร์โดยใช้ฟังก์ชันที่มีค่าของตาราง ขึ้นอยู่กับเขตเวลาที่ส่งผ่านไปยังฟังก์ชันนี้ข้อมูลสามารถคำนวณและส่งคืนจากตาราง utc หวังว่านี่จะทำให้คำตอบดั้งเดิมของฉันชัดเจนขึ้น
KNI

มันจะทำงานได้อย่างไรถ้ามีการรวบรวมข้อมูล? หากเขตเวลาคือ 30 นาทีชดเชยข้อมูลจะตกอยู่ในกลุ่มอื่น คุณไม่สามารถเปลี่ยนป้ายกำกับที่แสดงในเลเยอร์การนำเสนอ
Colin 't Hart
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.