การจัดเก็บ vs การคำนวณค่ารวม


96

มีแนวทางหรือกฎง่ายๆในการพิจารณาว่าจะเก็บค่ารวมและเมื่อใดในการคำนวณพวกเขาได้ทันทีหรือไม่

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

Ratings       Widgets
---------     -------
widget_id     widget_id
user_id       name              
rating        avg_rating  <--- The column in question

คำตอบ:


58

มันขึ้นอยู่กับ. การคำนวณค่าล่วงหน้าก่อนวางภาระการเขียนที่มากขึ้นทำให้การอ่านยากขึ้น

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

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

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


ฉันพบว่าการสนทนานี้มีประโยชน์มากกับมุมมองที่เป็นรูปธรรม มันปรับให้เข้ากับ Oracle แต่สามารถเข้าใจได้โดยทั่วไป สำหรับคนอย่างฉันที่มาจากพื้นหลัง MySQL มุมมอง MySQL แตกต่างจาก Materialized view มันเป็นเสมือนจริงและไม่เก็บลงดิสก์ (ดังที่ได้กล่าวไว้ในลิงก์ที่ฉันให้ไว้)
Siddhartha

upvoted! กำลังจะถามคำถามที่แน่นอนฉันจำเป็นต้องเก็บตัวชี้วัดเช่น SMA, EMA, WMA, RSI ฯลฯ และพวกเขาเกี่ยวข้องกับการคำนวณหนักฉันทำตารางในขณะนี้ซึ่งฉันเองรีเฟรชด้วยตนเองจนถึงปัจจุบันตัวชี้วัดเหล่านี้เปลี่ยน 100% ทุกครั้งด้วย ข้อมูลใหม่เข้ามาเป็นกลยุทธ์ที่ดีในการรักษาพวกเขาคืออะไรฉันรู้ว่ามุมมองจะแยกฐานข้อมูลออกจากกันอย่างสมบูรณ์ถ้าทุกคนเริ่มสอบถามมุมมองทางซ้ายและขวา
PirateApp

11

ความถี่ที่คุณต้องการในการคำนวณ / แสดงค่าที่สัมพันธ์กับความถี่ที่มีการเปลี่ยนแปลง / อัพเดท

ดังนั้นหากคุณมีเว็บไซต์ที่มีจำนวนการเข้าชม 10k ต่อวันที่แสดงค่าที่จะเปลี่ยนแปลงเพียงชั่วโมงละครั้งฉันจะคำนวณเมื่อค่าพื้นฐานเปลี่ยนแปลง (อาจเป็นทริกเกอร์ฐานข้อมูลอะไรก็ตาม)

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


ทุกๆ 15 นาที, 10 เมตริกที่เปลี่ยน 100% กับ 1,000 แถวต่อเมตริก
PirateApp

1
@PirateApp และดูได้กี่ครั้งในหน้าต่างเฉลี่ย 15 นาที สิ่งที่คุณสามารถทำได้คือสร้างมันตามคำขอครั้งแรกในหน้าต่าง 15 นาทีจากนั้นแคชมันสำหรับผู้ที่กดปุ่มโหลดซ้ำแล้วซ้ำอีก
Joe

มันจะเป็นบนเว็บไซต์ดังนั้นฉันคิดว่าอย่างน้อย 10,000 คนจะได้เห็นมันสำหรับ starters เว็บไซต์ไม่ได้อยู่เพื่อให้ไม่มีข้อมูลจริงเกี่ยวกับพฤติกรรมของผู้ใช้
PirateApp

1
ปัญหาคือจำนวนคำขอที่สัมพันธ์กับความถี่ที่เปลี่ยนแปลง ดังนั้นหากคุณสร้างบางสิ่งก่อนที่จะเห็น 10,000 ครั้งก่อนการเปลี่ยนแปลงข้อมูลพื้นฐานดังนั้นใช่สร้างไว้ล่วงหน้า หากมีการดูเพียงครั้งเดียวหรือน้อยกว่าหนึ่งครั้ง (เนื่องจากข้อมูลมีการเปลี่ยนแปลงอย่างรวดเร็วหรือเพราะหน้านั้นไม่ค่อยได้ดู) คุณก็จะไม่ทำเช่นนั้น
Joe

4

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

  • เพิ่งอ่าน
  • สิ้นเดือน
  • สำหรับผู้ใช้บางคนเมื่อเริ่มต้นวัน
  • ...

1
พวกเขาจะเข้าไปในคิวค้างได้อย่างไร?
jcolebrand

2
@ jcolebrand .. เป็นช่วงเวลาของการเพิ่ม / ลบคะแนน (ตารางคะแนน) สำหรับวิดเจ็ตบางตัว ในขณะนี้ค่าเฉลี่ยในตารางวิดเจ็ตไม่ถูกต้องดังนั้นเราต้องแทรกลงในตารางบันทึก StaleWidgets ที่มีเพียงหนึ่งคอลัมน์ - widget_id ใช้ทริกเกอร์หรือ proc ที่เก็บไว้ซึ่งแทรกการบันทึกไปยังตารางการจัดอันดับหรือตัวแปรของคุณ
garik

2

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

วิธีนี้คุณไม่จำเป็นต้องคำนวณใหม่ทุกครั้งคุณจะคำนวณเฉพาะเมื่อคุณต้องอ่านและคำนวณค่าคอลัมน์ใหม่เท่านั้น วิธีนี้คุณจะประหยัดการคำนวณใหม่จำนวนมาก


2

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

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

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