สิ่งที่มีคุณสมบัติ "คำขอฐานข้อมูลมากเกินไป" ในรหัส?


17

นี่คือการอภิปรายด้วยตนเองและเพื่อนร่วมงานบางคนของฉันมีและคิดว่าฉันจะออกมาที่นี่และดูว่ามีความเห็นเป็นเอกฉันท์เกี่ยวกับเรื่องนี้หรือไม่

โดยทั่วไปจะมีความคิดเห็น 2 ข้อต่อไปนี้ในการเรียกฐานข้อมูล: 1. ทำการโทรครั้งใหญ่เพื่อรับทุกสิ่งที่อาจจำเป็นในการลดฐานข้อมูลจำนวนการโทร DB 2. ทำการโทรแยกขนาดเล็กลงตามสิ่งที่ร้องขอเพื่อลดขนาดของ การเรียก DB

ที่ซึ่งสิ่งนี้กำลังเข้ามาเล่นโดยเฉพาะอย่างยิ่งอยู่ในรหัสทั่วไป เราจะใช้ตัวอย่างของคลาสพนักงานที่ค่อนข้างตรงไปตรงมา

สมมติว่าคลาสพนักงานของคุณมี 10 ค่าแอตทริบิวต์ (ชื่อนามสกุลจ้าง ฯลฯ ) แล้วแอตทริบิวต์ 2 คลาส ... 1 ชี้ไปที่แผนกระดับแล้ว 1 ผู้ควบคุมที่ชี้กลับไปยังวัตถุพนักงานอื่น

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

ในใจชุดที่ 2 คุณจะเติมข้อมูลอ็อบเจกต์ของพนักงานในตอนแรกจากนั้นใส่เฉพาะออบเจ็กต์ของแผนกและหัวหน้างานหากมีการร้องขอจริงๆ

ท่าทางของ 2 ค่อนข้างตรงไปตรงมา ... ลดขนาดของคำขอและจำนวนวัตถุฐานข้อมูลที่ต้องกดแต่ละครั้งที่มีการร้องขอ ท่าทางที่ # 1 คือแม้ว่ามันจะสามารถดำเนินการได้อย่างถูกต้องความจริงที่แท้จริงว่ารหัสจะต้องทำให้การเชื่อมต่อหลาย ๆ จะทำให้เกิดความเครียดมากขึ้นในการเชื่อมต่อระหว่างเว็บเซิร์ฟเวอร์และฐานข้อมูลเมื่อเทียบกับการลดมัน

แรงผลักดันที่อยู่เบื้องหลังการค้นคว้าสิ่งนี้คือปริมาณการรับส่งข้อมูลระหว่างเว็บเซิร์ฟเวอร์และเซิร์ฟเวอร์ฐานข้อมูลของเราไม่สามารถควบคุมได้


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

3
อาจเกี่ยวข้องกับปัญหา +1 + stackoverflow.com/questions/97197/…
Valera Kolupaev

@Valera: เพื่อความสะดวกนี่คือลิงค์ที่โพสต์ในคำถามนั้น: realsolve.co.uk/site/tech/hib-tip-pitfall.php?name=n1selects
rwong

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

คำตอบ:


8

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

ขึ้นอยู่กับภาษาและกรอบงานที่คุณใช้อาจมีกรอบแคชที่สามารถทำบางสิ่ง (หรือส่วนใหญ่) ในสิ่งที่คุณต้องการ หากคุณใช้ Java คุณสามารถดูApache Commons-Cache (ฉันไม่ได้ใช้มาระยะหนึ่งแล้วและในขณะที่ดูเหมือนว่าอยู่เฉยๆก็ยังคงใช้งานได้และมันก็ค่อนข้างดีในครั้งสุดท้ายที่ฉันใช้มัน)


3

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

สำหรับสิ่งที่จัดประเภทมากเกินไปนั้นขึ้นอยู่กับแอปพลิเคชัน สำหรับเว็บแอพพลิเคชั่นส่วนใหญ่ทุกอย่างที่อยู่ใน 30 วินาทีนั้นเป็นที่ยอมรับ ฉันจะพูดกับผู้ใช้ของคุณเกี่ยวกับความคาดหวังของพวกเขา


อะไรคือการเรียก db db ที่เขียนไม่ดี?
nu everest

3

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


3

นี่เป็นกฎที่ฉันใช้บางทีพวกเขาอาจจะใช้กับคุณ

  1. วัดก่อน! ฉันจะไม่แม้แต่ดูรหัสว่า "อาจช้า" เว้นแต่ฉันจะเห็นการรับส่งข้อมูลที่ไหลไปยังทรัพยากรนั้นและทรัพยากรนั้นจะตอบสนองช้า
  2. 1 คำขอ = ข้อความค้นหา K จำนวนครั้งที่ฉันพูดคุยกับฐานข้อมูลนั้นขึ้นอยู่กับประเภทของทรัพยากรที่ร้องขอ และไม่เคยเป็นไปตามลักษณะของการร้องขอหรือสถานะของทรัพยากรนั้น ในตัวอย่างของคุณนั่นอาจเป็นได้มากที่สุด 3 คำสั่ง: 1 สำหรับพนักงาน, 1 สำหรับแผนกและ 1 สำหรับผู้บังคับบัญชา; มันไม่สำคัญหรอกว่าแต่ละอันนั้นมีอยู่เท่าไหร่
  3. อย่าสอบถามสิ่งที่คุณจะไม่ใช้ หากนี่คือ HTTP ที่เรากำลังพูดถึงจะไม่มีเหตุผลในการสืบค้นข้อมูลในภายหลัง ไม่ช้า แต่ละคำขอเริ่มต้นจากกระดานชนวนสะอาด บางครั้งฉันต้องการคอลัมน์ส่วนใหญ่จากตาราง แต่ในบางครั้งฉันต้องการเพียงหนึ่งหรือสอง เมื่อฉันรู้ว่าฉันต้องการทุ่งอย่างแน่นอนฉันจะขอแค่นั้น
  4. โยนฮาร์ดแวร์ที่มีปัญหา เซิร์ฟเวอร์ราคาถูก; บางครั้งคุณสามารถเพิ่มประสิทธิภาพได้เพียงแค่ย้ายฐานข้อมูลไปยังกล่องที่มีเนื้อวัวมากขึ้น หรือส่งแบบสอบถามบางอย่างไปยังแบบจำลองแบบอ่านอย่างเดียว
  5. ขั้นแรกทำให้แคชใช้ไม่ได้จากนั้นนำไปใช้แคช การกระตุ้นให้ใช้บ่อยหรือยากที่จะสืบค้นข้อมูลในแคชนั้นรุนแรง แต่ข้อมูลที่ไม่ได้ใช้งานทั้งหมดหรือข้อมูลที่ถูกแทนที่ที่หมดอายุจะถูกมองข้าม หากคุณรู้วิธีนำข้อมูลออกจากแคช ถ้าอย่างนั้นคุณก็เก็บมันไว้ในแคชอย่างปลอดภัย หากปรากฏว่ามีราคาแพงกว่าในการทำให้แคชใช้ไม่ได้ จากนั้นคุณไม่ต้องการแคช

2

ทั้งสองกลยุทธ์ที่นี่ใช้ได้อย่างสมบูรณ์ มีข้อดีและข้อเสียในแต่ละ:

หนึ่งสายสำหรับวัตถุทั้ง 3:

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

หนึ่งสายต่อวัตถุ (รวม 3 สาย)

  • ให้การโทรทั่วไปเพื่อเติมอินสแตนซ์เดียวของแต่ละประเภทวัตถุ พวกเขาสามารถใช้งานได้อย่างอิสระ
  • จะสามารถบำรุงรักษาได้มากขึ้นเนื่องจากโครงสร้างแบบสอบถามจะง่ายขึ้น
  • จะช้าลง (ไม่จำเป็นต้องช้ากว่า 3 เท่า แต่เพิ่มโอเวอร์เฮดสำหรับข้อมูลเดียวกัน)
  • สามารถทำให้เกิดปัญหากับการดึงข้อมูลที่ไม่จำเป็น (ดึงระเบียนทั้งหมดเมื่อคุณต้องการหนึ่งเขตข้อมูลจะสิ้นเปลือง)
  • อาจทำให้เกิดปัญหา N + 1 เมื่อมีความสัมพันธ์แบบหลายต่อหนึ่งอยู่หากมีการส่งแบบสอบถามแบบระเบียนเดียวระเบียน N ครั้งจะมีหนึ่งรายการต่อระเบียนในคอลเลกชัน

ในการตอบข้อกังวลของคุณสองสามข้อ (# 3 และ 5 ในรายการที่สอง) ... จะเกิดอะไรขึ้นถ้าหัวหน้างานและแผนกใช้เวลาเพียง 1/3 (หรือน้อยกว่า)? จะเกิดอะไรขึ้นถ้ารหัสถูกออกแบบมาเพื่อให้เด็กทุกคนทันทีที่วัตถุ List <> ที่ให้รหัสเพื่อบรรจุพวกเขาถูกอ้างอิงเป็นครั้งแรก ... นั่นจะช่วยบรรเทาความวุ่นวายได้หรือไม่?
user107775

หากวัตถุเสริมไม่ค่อยจำเป็นเพียงแค่ในกรณีทั่วไปสิ่งนี้จะทำงานได้เร็วขึ้น (ข้อมูลน้อยลงเพื่อดึงข้อมูล) แต่กรณีที่เลวร้ายที่สุดจะช้าลง (ข้อมูลเดียวกันหรือเรียกคืนได้มากกว่าโดยใช้ค่าใช้จ่ายในการสื่อสารสามครั้งจากคอมพิวเตอร์ของคุณ) สำหรับปัญหา N + 1 คุณเพียงแค่ต้องสามารถสร้างแบบสอบถามที่ดึงรายการของวัตถุเพื่อให้สามารถทำได้โดยขึ้นอยู่กับ foreign key ไปที่ด้าน "หนึ่ง" ของความสัมพันธ์แล้วดึงหลายแถว ออกจากผลการสืบค้น คุณไม่สามารถใช้รุ่นของแบบสอบถามที่จะต้องมีคีย์หลักของบันทึก
KeithS

1

สำหรับฉันคำขอฐานข้อมูลจำนวนมากเกินไปกำลังส่งคำขอมากกว่าที่คุณต้องการโหลดข้อมูลที่คุณต้องการในเวลาใดก็ตาม

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

ดังนั้นมีตัวเลือกทั้งสองและใช้แต่ละสถานการณ์ที่เรียกมัน

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


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

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

1

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

การทำเช่นนี้ทั้งหมดในนัดเดียวจะทำให้โค้ดไม่สามารถรักษาได้ โดยปกติแล้วจะมีการเพิ่มเลเยอร์ abstraction เพิ่มเติม: โค้ดกำหนดตารางเวลาการร้องขอหลายครั้งตามที่ต้องการจากนั้นเอ็นจินจะแยกวิเคราะห์คำขอนี้เป็นคำขอขนาดใหญ่หนึ่งคำขอ (อาจใช้แคชระหว่างทาง)

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

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


1

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

มันจะน่าสนใจที่จะรู้ว่าสิ่งนี้มาจากหน่วยความจำ db เทียบกับดิสก์ ไม่มีอะไรที่ทำให้ฉันรู้สึกว่าแผนกมีแนวโน้มที่จะเปลี่ยนแปลงมากขึ้นหรือน้อยลงเมื่อเทียบกับที่อยู่

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