จัดกลุ่มตามชั่วโมงในชุดข้อมูลขนาดใหญ่


12

ใช้ MS SQL 2008 ฉันกำลังเลือกเขตข้อมูลเฉลี่ยจาก 2.5 ล้านระเบียน แต่ละระเบียนแสดงถึงหนึ่งวินาที MyField เป็นค่าเฉลี่ยรายชั่วโมงของบันทึก 1 วินาทีเหล่านั้น แน่นอนว่าซีพียูเซิร์ฟเวอร์ฮิต 100% และการเลือกใช้เวลานานเกินไป ฉันจำเป็นต้องบันทึกค่าเฉลี่ยเหล่านั้นเพื่อให้ SQL ไม่จำเป็นต้องเลือกระเบียนเหล่านั้นทั้งหมดในแต่ละคำขอ สิ่งที่สามารถทำได้?

  SELECT DISTINCT
         CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR) AS TimeStampHour,
         MIN([timestamp]) as TimeStamp,
         AVG(MyField) As AvgField
    FROM MyData
   WHERE TimeStamp > '4/10/2011'
GROUP BY CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR)
ORDER BY TimeStamp

6
TimeStamp เป็นส่วนหนึ่งของดัชนีคลัสเตอร์หรือไม่ มันควรจะเป็น ...

@antisanity - ทำไม เขากำลังใช้งาน CPU สูงสุดไม่ใช่ดิสก์ io
แจ็คบอกว่าลอง topanswers.xyz

คำตอบ:


5

ส่วนของการค้นหากำลังขยาย CPU เป็นระยะเวลานานคือฟังก์ชันในส่วน GROUP BY clause และข้อเท็จจริงที่ว่าการจัดกลุ่มนั้นจะต้องมีการเรียงลำดับที่ไม่ได้ทำดัชนีในอินสแตนซ์นี้เสมอ ในขณะที่ดัชนีในฟิลด์การประทับเวลาจะช่วยให้ตัวกรองเริ่มต้นการดำเนินการนี้จะต้องดำเนินการในทุกแถวที่ตัวกรองจับคู่ การเร่งความเร็วนี้กำลังใช้เส้นทางที่มีประสิทธิภาพมากขึ้นในการทำงานเช่นเดียวกับที่อเล็กซ์แนะนำ แต่คุณก็ยังมีความไร้ประสิทธิภาพอยู่ที่นั่นเพราะการรวมฟังก์ชั่นที่คุณเคยใช้กับตัววางแผนแบบสอบถามจะไม่สามารถเกิดขึ้นได้ สิ่งที่จะได้รับการช่วยเหลือจากดัชนีใด ๆ ดังนั้นจึงจะต้องเรียกใช้ผ่านทุกแถวก่อนที่จะเรียกใช้ฟังก์ชันเพื่อคำนวณค่าการจัดกลุ่มจากนั้นสามารถสั่งข้อมูลและคำนวณผลรวมของการจัดกลุ่มที่เกิดขึ้นได้

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

คุณสามารถรักษาคอลัมน์พิเศษสำหรับแต่ละแถวที่มีเวลาปัดเศษเป็นชั่วโมงและจัดทำดัชนีคอลัมน์นี้เพื่อใช้ในแบบสอบถามดังกล่าว นี่คือการทำให้ข้อมูลของคุณเสื่อมสภาพดังนั้นอาจรู้สึกว่า "สกปรก" แต่จะใช้งานได้และจะสะอาดกว่าการแคชมวลรวมทั้งหมดเพื่อใช้ในอนาคต (และอัปเดตแคชนั้นเมื่อมีการเปลี่ยนแปลงข้อมูลพื้นฐาน) คอลัมน์พิเศษควรได้รับการบำรุงรักษาโดยทริกเกอร์หรือเป็นคอลัมน์ที่คำนวณแล้วจะยังคงอยู่โดยไม่ได้รับการบำรุงรักษาด้วยตรรกะที่อื่นเนื่องจากจะรับประกันตำแหน่งปัจจุบันและอนาคตทั้งหมดที่อาจแทรกข้อมูลหรืออัปเดตคอลัมน์ประทับเวลาหรือแถวที่มีอยู่ คอลัมน์. คุณยังสามารถลบ MIN (การประทับเวลา) ออกได้ สิ่งที่แบบสอบถามจะส่งผลให้ในลักษณะนี้ยังคงเดินลงแถวทั้งหมด (นี้ไม่สามารถหลีกเลี่ยงได้ชัด) แต่มันสามารถทำดัชนีเพื่อ เอาท์พุทแถวสำหรับการจัดกลุ่มแต่ละกลุ่มตามที่ได้รับไปยังค่าถัดไปในดัชนีแทนที่จะต้องจดจำชุดของแถวทั้งหมดสำหรับการดำเนินการเรียงลำดับที่ไม่ได้จัดทำดัชนีก่อนที่จะทำการจัดกลุ่ม / การรวมได้ มันจะใช้หน่วยความจำน้อยลงเช่นกันเนื่องจากไม่จำเป็นต้องจำแถวใด ๆ จากค่าการจัดกลุ่มก่อนหน้าเพื่อประมวลผลแถวที่กำลังดูอยู่ตอนนี้หรือที่เหลือ

วิธีการนั้นจะลบความต้องการค้นหาบางอย่างในหน่วยความจำสำหรับชุดผลลัพธ์ทั้งหมดและทำการเรียงลำดับที่ไม่ได้ทำดัชนีสำหรับการดำเนินการกลุ่มและลบการคำนวณค่ากลุ่มออกจากแบบสอบถามขนาดใหญ่ (ย้ายงานนั้นออกไปยัง INSERTs / UPDATE ข้อมูล) และควรอนุญาตให้แบบสอบถามดังกล่าวสามารถทำงานได้อย่างยอมรับได้โดยไม่จำเป็นต้องเก็บรักษาผลลัพธ์ที่รวบรวมไว้แยกจากกัน

วิธีการที่ไม่ทำให้ข้อมูลของคุณว่างเปล่า แต่ยังต้องการโครงสร้างเพิ่มเติมคือใช้ "ตารางเวลา" ในกรณีนี้ตารางหนึ่งมีหนึ่งแถวต่อชั่วโมงตลอดเวลาที่คุณต้องการพิจารณา ตารางนี้จะไม่ใช้พื้นที่จำนวนมากใน DB หรือขนาดที่ประเมินได้ - เพื่อครอบคลุมช่วงเวลา 100 ปีต่อตารางที่มีหนึ่งแถวของสองวันที่ (จุดเริ่มต้นและจุดสิ้นสุดของชั่วโมงเช่น '2011-01-01 @ 00: 00: 00.0000 ',' 2011-01-01 @ 00: 00: 59.9997 ', "9997" เป็นจำนวนมิลลิวินาทีที่น้อยที่สุดในฟิลด์ DATETIME จะไม่ปัดขึ้นเป็นวินาทีถัดไป) ซึ่งเป็นส่วนหนึ่งของ คีย์หลักที่ทำคลัสเตอร์จะใช้พื้นที่ ~ 14Mbyte (8 + 8 ไบต์ต่อแถว * 24 ชั่วโมง / วัน * 365.25 วัน / ปี * 100 บวกบิตสำหรับค่าใช้จ่ายของโครงสร้างต้นไม้ดัชนีดัชนี แต่ค่าใช้จ่ายนั้นไม่มีนัยสำคัญ) .

SELECT CONVERT(VARCHAR, [timestamp], 1)+' '+ CAST(DATEPART(Hh,[timestamp]) as VARCHAR) AS TimeStampHour
     , MIN([timestamp]) as TimeStamp
     , AVG(MyField) As AvgField
FROM TimeRangeByHours tt
INNER JOIN MyData md ON md.TimeStamp BETWEEN tt.StartTime AND tt.EndTime
WHERE tt.StartTime > '4/10/2011'
GROUP BY tt.StartTime
ORDER BY tt.StartTime

ซึ่งหมายความว่าตัววางแผนคิวรีสามารถจัดเรียงดัชนีใน MyData.TimeStamp ที่จะใช้ ตัววางแผนคิวรีควรมีความสว่างเพียงพอที่จะคำนวณว่ามันสามารถเดินลงตารางเชื่องในขั้นตอนที่มีดัชนีบน MyData.TimeStamp อีกครั้งหนึ่งแถวต่อกลุ่มเอาท์พุทเอาท์พุทอีกครั้งและทิ้งแต่ละชุด ไม่มีการจัดเก็บแถวกลางทั้งหมดที่ไหนสักแห่งใน RAM จากนั้นทำการเรียงลำดับที่ไม่ได้จัดทำดัชนีไว้ แน่นอนว่าวิธีนี้ต้องการให้คุณสร้างตารางเวลาและตรวจสอบให้แน่ใจว่ามันครอบคลุมทั้งหลังไปข้างหน้าและข้างหลังมากพอ แต่คุณสามารถใช้ตารางเวลาสำหรับการสืบค้นกับเขตข้อมูลวันที่จำนวนมากในแบบสอบถามที่แตกต่างกัน คอลัมน์ที่คำนวณพิเศษสำหรับแต่ละฟิลด์วันที่ที่คุณต้องการกรอง / กลุ่มด้วยวิธีนี้และขนาดที่เล็กของตาราง (ยกเว้นว่าคุณต้องการให้มีช่วง 10

วิธีการตารางเวลามีความแตกต่างพิเศษ (ที่อาจเป็นประโยชน์มาก) เมื่อเทียบกับสถานการณ์ปัจจุบันของคุณและวิธีการคำนวณคอลัมน์: มันสามารถคืนแถวในช่วงเวลาที่ไม่มีข้อมูลเพียงแค่เปลี่ยน INNER JOIN ในแบบสอบถามตัวอย่างด้านบน เป็นคนซ้ายอย่างเดียว

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

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


3

ดูคำถามนี้ ( กำหนดวันที่ ) และทำไมต้องกังวลกับการแปลงทุกอย่างเป็นสตริง - คุณสามารถทำได้ในภายหลัง (ถ้าคุณต้องการ)

  SELECT DISTINCT
         dateadd(hour,datediff(hour,0,[timestamp]),0) AS TimeStampHour,
         MIN([timestamp]) as TimeStamp,
         AVG(MyField) As AvgField
    FROM MyData
   WHERE TimeStamp > '4/10/2011'
GROUP BY dateadd(hour,datediff(hour,0,[timestamp],0);
ORDER BY TimeStamp

1

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

หากคุณต้องการทำให้เร็วขึ้นคุณต้องมีดัชนีในฟิลด์ TimeStamp อย่างแน่นอน นอกจากนี้ฉันขอแนะนำให้ใช้สิ่งนี้เพื่อแปลงเป็นชั่วโมง:

select convert(varchar(13), getdate(), 121)

หากคุณต้องการสร้างสแนปชอตและนำมาใช้ใหม่ในภายหลังinsert intoเพื่อสร้างตารางใหม่พร้อมผลลัพธ์จากแบบสอบถามของคุณ ดัชนีตารางตามและใช้งาน จากสิ่งที่ฉันเข้าใจคุณจะต้องมีดัชนีใน TimeStampHour

นอกจากนี้คุณสามารถตั้งค่างานที่รวบรวมข้อมูลรายวันในตารางรวมใหม่ของคุณ


-1

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


1
-1 - ไม่คุณไม่ได้ "ทำให้มันเป็นดัชนีที่ไม่ได้ผูกติดกับทุกแถวในฐานข้อมูล" - ดัชนีใด ๆ ที่TimeStampจะยังคงใช้ในการกรองแถว
แจ็คพูดว่าลอง topanswers.xyz

-3

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

หากคุณมีเงินคุณสามารถพิจารณาซื้อนักประวัติศาสตร์ข้อมูลกระบวนการเฉพาะเช่น:

  1. ปริญญาเอกที่ Honeywell สม่ำเสมอ
  2. Osisoft PI
  3. Aspentech IP21
  4. เป็นต้น

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

.. และในบันทึกทั่วไป: ฉันพยายามหลีกเลี่ยงการใช้DISTINCTคำหลักเสมอเมื่อเขียน SQL มันเป็นความคิดที่ดี ในกรณีของคุณคุณควรจะสามารถวางDISTINCTและรับผลลัพธ์เดียวกันโดยเพิ่มMIN([timestamp])ไปยังGROUP BYข้อของคุณ


1
มันไม่ถูกต้องจริงๆ ฐานข้อมูลเชิงสัมพันธ์นั้นสมบูรณ์แบบสำหรับบันทึก 2.5 ล้านรายการ และเขาไม่ได้ทำร่วมกับโต๊ะจำนวนมาก ข้อบ่งชี้แรกที่คุณต้องการทำให้ข้อมูลผิดปกติหรือย้ายไปยังระบบที่ไม่เกี่ยวข้องคือเมื่อคุณทำการเชื่อมต่อที่มีขนาดใหญ่และซับซ้อนในตารางจำนวนมาก ชุดข้อมูลของผู้โพสต์ดูเหมือนจะใช้ระบบฐานข้อมูลเชิงสัมพันธ์ที่ยอมรับได้อย่างสมบูรณ์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.