ข้อดีและข้อเสียของการคำนวณใน SQL และแอปพลิเคชันของคุณคืออะไร


154

shopkeeper ตารางมีฟิลด์ต่อไปนี้:

id (bigint),amount (numeric(19,2)),createddate (timestamp)

สมมุติว่าฉันมีตารางด้านบน ฉันต้องการรับบันทึกเมื่อวานและสร้างรายงานโดยพิมพ์จำนวนเงินเป็นเซนต์

วิธีหนึ่งในการทำคือการคำนวณในแอปพลิเคชัน java ของฉันและดำเนินการแบบสอบถามง่าย ๆ

Date previousDate ;// $1 calculate in application

Date todayDate;// $2 calculate in application

select amount where createddate between $1 and $2 

จากนั้นวนรอบบันทึกและแปลงจำนวนเงินเป็นเซ็นต์ในแอปพลิเคชัน java ของฉันและสร้างรายงาน

อีกวิธีหนึ่งก็เหมือนกับการคำนวณในแบบสอบถามของ sql:

select cast(amount * 100 as int) as "Cents"
from shopkeeper  where createddate  between date_trunc('day', now()) - interval '1 day'  and  date_trunc('day', now())

จากนั้นวนซ้ำผ่านระเบียนและสร้างรายงาน

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

กรณีการใช้งานด้านบนเป็นเพียงตัวอย่างในสถานการณ์จริงตารางอาจมีคอลัมน์จำนวนมากที่ต้องการการประมวลผลที่คล้ายกัน

คุณช่วยบอกฉันทีว่าแนวทางใดดีกว่าในแง่ของประสิทธิภาพและด้านอื่น ๆ และเพราะอะไร


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

คำตอบ:


206

มันขึ้นอยู่กับปัจจัยหลายอย่าง แต่ส่วนใหญ่ที่สำคัญที่สุด:

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

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

บันทึกย่อของคุณอีกครั้ง:

แล้ววนซ้ำระเบียน

การวนลูปผ่านบันทึกมักจะเป็นสิ่งที่ผิดที่ต้องทำใน sql - การเขียนการดำเนินงานแบบ set-based เป็นที่ต้องการ

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

พิจารณาด้วยเช่นกัน: ถ้าสิ่งนี้มีราคาแพงมากมันจะถูกเก็บไว้ที่อื่นได้ไหม?

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


การวนซ้ำหมายถึงการประมวลผล "แถวต่อครั้ง" มากขึ้นหรือน้อยลง และนั่นหมายถึง 2 * เวลาในการตอบสนองของเครือข่ายบวกสี่บริบทสลับไปมา ใช่: นั่นแพง การดำเนินการ "ดั้งเดิม" DBMS ทำงานอย่างหนักเพื่อลดขนาดดิสก์ -I / O (การเรียกระบบ) แต่จัดการเพื่อดึงข้อมูลมากกว่าหนึ่งแถวต่อการเรียกระบบ แถวต่อครั้งใช้เวลาอย่างน้อยสี่การเรียกระบบ
wildplasser

@ Wildplasser ไม่จำเป็น เซิร์ฟเวอร์อาจเป็นสตรีมมิ่งแถวที่คุณใช้เมื่อมาถึง - อุปมา "reader" ไม่ใช่เรื่องแปลก
Marc Gravell

1
@ Marc Cavell: ก็แล้วแต่ ในกรณีที่ footprint ของแอปพลิเคชันโปรแกรมเป็นเพียงหนึ่งเร็กคอร์ดแบบลอจิคัลมันก็จะมากหรือน้อยตกลง แต่ส่วนใหญ่ของ "กรอบ" ฉันรู้ว่ามักจะดูดในระเบียนทั้งหมดเมื่อเริ่มต้นและยิงพวกเขาออกหนึ่งโดยหนึ่ง การล็อคเป็นอันตรายอีกอย่างหนึ่ง
wildplasser

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

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

86

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

เท่าที่เกี่ยวข้องกับPostgreSQLคุณสามารถทำเกือบทุกอย่างบนเซิร์ฟเวอร์ได้อย่างมีประสิทธิภาพ RDBMS เก่งในการสืบค้นที่ซับซ้อน สำหรับความต้องการขั้นตอนคุณสามารถเลือกภาษาสคริปต์ฝั่งเซิร์ฟเวอร์ที่หลากหลาย: tcl, python, perl และอื่น ๆ อีกมากมาย ส่วนใหญ่ผมใช้PL / pgSQLแม้ว่า

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

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

การย้อนกลับไปมาระหว่างแอปและเซิร์ฟเวอร์มีราคาแพง สำหรับเซิร์ฟเวอร์และไคลเอนต์ พยายามลดสิ่งนั้นลงและคุณจะได้รับ - ergo: ใช้โพรซีเดอร์ฝั่งเซิร์ฟเวอร์และ / หรือ SQL ที่ซับซ้อนหากจำเป็น

เราเพิ่งเสร็จสิ้นโครงการที่เรารวบรวมแบบสอบถามที่ซับซ้อนเกือบทั้งหมดไว้ในฟังก์ชั่น Postgres แอปมอบพารามิเตอร์และรับชุดข้อมูลที่ต้องการ รวดเร็วสะอาดง่าย (สำหรับนักพัฒนาแอป) I / O ลดลงเหลือเพียง ... สร้อยคอที่มีความเงางามพร้อมรอยเท้าคาร์บอนต่ำ


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

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

1
สิ่งที่ฉันเห็นด้วยฉันไม่คิดว่ามันจะเป็นเรื่องเลวร้ายเสมอไปที่จะทำการคำนวณแบบวนซ้ำใน SQL @a_horse_with_no_name บางครั้งสิ่งนี้จะต้องทำต่อไป หรือคุณต้องทำซ้ำในราคาเมื่อดึงข้อมูลกลับมา
zinking

-1 เพราะมันเป็นอาร์กิวเมนต์ด้านเดียวละเว้นการแลกเปลี่ยนและตั้งชายฟางสำหรับฝั่งตรงข้ามแทนที่จะพิจารณาและ refuting กรณีที่ดีที่สุดของฝ่ายตรงข้าม "การกลับไปกลับมาระหว่างแอพและเซิร์ฟเวอร์มีราคาแพง" - แน่นอน: แต่มันไม่ได้เป็นเพียงสิ่งเดียวที่มีราคาแพงและค่าใช้จ่ายต่างๆจะต้องถูกชั่งน้ำหนักต่อกัน มันอาจกลายเป็นว่าแบบสอบถาม SQL ที่ซับซ้อนหรือขั้นตอนการจัดเก็บนั้นดีที่สุดสำหรับกรณีนั้น ๆ แต่รายละเอียดของคดีโดยทั่วไปจะต้องนำมาพิจารณาเมื่อทำการตัดสินใจแบบนั้น
yfeldblum

เจ๋งเปรียบเทียบ แต่น่าเสียดายที่มันตั้งอยู่บนสมมติฐานที่ผิด การขนส่งแร่ทองคำเป็นเรื่องธรรมดามาก อัตราส่วนการปอกต่อทองคำจะอยู่ที่ประมาณ 1: 1 (ต่อขยะทองคำ) อย่างไรก็ตามมักจะถูกกว่าในการประมวลผลนอกสถานที่ซึ่งมีอุปกรณ์และคุณภาพของงานที่ดีกว่า ขึ้นอยู่กับขนาดของการจัดส่งการเพิ่มประสิทธิภาพการประมวลผล 0.1% อาจช่วยให้รายได้เพิ่มขึ้นเมื่อเทียบกับรายได้ (แม้จะมีราคาจัดส่งเป็นสองเท่า) เนื่องจากทองคำมีราคาแพงในทุกวันนี้ โดยทั่วไปแล้วแร่อื่น ๆ เช่นเหล็กจะถูกจัดส่งด้วยเช่นกัน (อัตราส่วนการปอกของเหล็กประมาณ 60%!)
Chris Koston

18

ในกรณีนี้คุณน่าจะดีกว่าการคำนวณใน SQL เล็กน้อยเนื่องจากเอ็นจินฐานข้อมูลมีแนวโน้มที่จะมีรูทีนเลขฐานสิบที่มีประสิทธิภาพมากกว่าจาวา

โดยทั่วไปแม้ว่าการคำนวณระดับแถวจะไม่แตกต่างกันมากนัก

มันจะสร้างความแตกต่างที่ไหน:

  • การคำนวณโดยรวมเช่น SUM (), AVG (), MIN (), MAX () ที่นี่โปรแกรมฐานข้อมูลจะมีลำดับความสำคัญเร็วกว่าการนำ Java ไปใช้
  • ทุกการคำนวณจะใช้ในการกรองแถว การกรองที่ฐานข้อมูลนั้นมีประสิทธิภาพมากกว่าการอ่านแถวแล้วละทิ้งมัน

12

ไม่มีขาวดำเกี่ยวกับส่วนของตรรกะการเข้าถึงข้อมูลที่ควรดำเนินการใน SQL และควรดำเนินการส่วนใดในแอปพลิเคชันของคุณ ฉันชอบถ้อยคำของ Mark Gravellโดยแยกแยะระหว่าง

  • การคำนวณที่ซับซ้อน
  • การคำนวณที่เน้นข้อมูล

กำลังไฟและการแสดงออกของ SQL ต่ำเกินไป ตั้งแต่เปิดตัวฟังก์ชั่นหน้าต่างการคำนวณที่ไม่มุ่งเน้นจำนวนมากสามารถทำได้อย่างง่ายดายและสวยงามในฐานข้อมูล

กฎสามข้อควรปฏิบัติตามเสมอโดยไม่คำนึงถึงสถาปัตยกรรมแอปพลิเคชันโดยรวม:

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

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

อ่านเพิ่มเติมที่อธิบายสิ่งเหล่านี้:


2

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

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


สามารถนำมาใช้ซ้ำได้ที่ระดับใด ๆ และไม่ใช่เหตุผล (ประสิทธิภาพที่ชาญฉลาด) เพื่อวางการคำนวณเพิ่มเติมใน SQL "โดยทั่วไปกล่องฐานข้อมูล": นี่เป็นสิ่งที่ผิดและยิ่งกว่านั้นในขณะที่มาร์คกราเวลล์กล่าวว่าการปรับขนาดใช้งานไม่ได้ในแบบเดียวกัน ฐานข้อมูลส่วนใหญ่ต้องการฮาร์ดแวร์เล็ก ๆ เพื่อให้รันได้อย่างเหมาะสมและรูปแบบประสิทธิภาพนั้นเกี่ยวข้องกับแอพพลิเคชั่นเซิร์ฟเวอร์เพียงเล็กน้อย (เช่นฉันจะใช้งบประมาณ 2 / 3rds ของฉันสำหรับเซิร์ฟเวอร์ SQL บน godlike IO ในขณะที่ฉันจะไม่ใช้จ่ายมากขึ้น กว่าสองสามร้อยสำหรับกองจัดเก็บข้อมูลของ appserver)
Morg

1

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

ลองคิดดูสองขั้นตอน: (1) การทำธุรกรรม OLTP (บันทึกจำนวนน้อย) (2) OLAP (สแกนหลายรายการแบบยาว)

ในกรณี OLTP ถ้าคุณต้องการรวดเร็ว (10k - 100k ธุรกรรมต่อวินาที) คุณต้องลบ latch, lock และ dead contention จากฐานข้อมูล ซึ่งหมายความว่าคุณต้องกำจัดแผงลอยยาวในการทำธุรกรรม: การเดินทางไปกลับจากลูกค้าไปยังฐานข้อมูลเพื่อย้ายการประมวลผลไปยังลูกค้าเป็นหนึ่งในคอกยาว คุณไม่สามารถทำธุรกรรมได้ยาวนาน (เพื่อให้อ่าน / อัปเดตอะตอมมิก) และมีปริมาณงานสูงมาก

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

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


0

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

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

มีแง่มุมอื่น ๆ อีกมากมายที่คุณสามารถคิดได้ก่อนตัดสินใจวางรหัส การรับรู้หนึ่งครั้งนั้นผิดทั้งหมด - ทุกอย่างสามารถทำได้ดีที่สุดใน Java (รหัสแอป) และ / หรือทุกอย่างดีที่สุดที่จะทำได้โดย db (sql code)


0

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

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


0

สิ่งสำคัญที่สุดคือ "ประสิทธิภาพ" ไม่ได้ถูกกำหนดไว้

สิ่งที่สำคัญสำหรับฉันมากที่สุดคือเวลาสำหรับนักพัฒนา

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


0

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

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

แม้ว่าคุณจะมีเลเยอร์กลางที่เหมาะสม (จากตัวอย่างที่ให้มาดูเหมือนว่าไม่ใช่กรณี) เลเยอร์นั้นอาจเปลี่ยนแปลงและ JBoss อาจกลายเป็น Ruby / Rails

ในทางกลับกันมันไม่น่าเป็นไปได้ที่คุณจะแทนที่ SQL-backend ด้วยสิ่งที่ไม่ใช่ DB เชิงสัมพันธ์ด้วย SQL และแม้ว่าคุณจะทำเช่นนั้นคุณจะต้องเขียน front-end ตั้งแต่เริ่มต้นดังนั้นประเด็นก็คือสิ่งที่สงสัย

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


หากคุณเปลี่ยนจาก jboss เป็น ruby ​​เป็นไปได้มากว่าคุณจะเปลี่ยน db (และคุณจะต้องนำการคำนวณเหล่านี้มาใช้) และก็ไม่น่าเป็นไปได้ที่คุณจะเปลี่ยนเป็นสิ่งที่แตกต่างกันมากขึ้นเช่น nosql
Dainius

0

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

ในสถาปัตยกรรมส่วนใหญ่จะเป็นเซิร์ฟเวอร์ SQL ที่ประกอบขึ้นเป็นแกนกลางของระบบและระบบภายนอกที่เพิ่มเข้ามา

แต่คณิตศาสตร์ข้างต้นนั้นช่างน่ารำคาญเหลือเกินเว้นแต่ว่าคุณจะผลักระบบของคุณไปสู่จุดที่ดีที่สุดในการวางไว้ในตำแหน่งที่คุณต้องการวางไว้ หากคณิตศาสตร์นั้นไม่สำคัญเช่นการคำนวณ sin / cos / tan เพื่อพูดการคำนวณระยะทางความพยายามนั้นอาจจะไม่ไร้สาระและต้องมีการวางแผนและทดสอบอย่างระมัดระวัง


0

คำตอบอื่น ๆ สำหรับคำถามนี้น่าสนใจ น่าแปลกที่ไม่มีใครตอบคำถามของคุณ คุณกำลังสงสัย:

  1. มันจะดีกว่าที่จะส่งไปยังเซ็นต์ในแบบสอบถามหรือไม่ ฉันไม่คิดว่าการส่งไปเซ็นต์จะเพิ่มอะไรในการค้นหาของคุณ
  2. มันจะดีกว่าที่จะใช้ตอนนี้ () ในการค้นหา? ฉันต้องการส่งวันที่ไปยังแบบสอบถามแทนการคำนวณในแบบสอบถาม

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

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


0

ขอยกตัวอย่างจริงเพื่อตอบคำถามนี้

ฉันต้องการคำนวณค่าเฉลี่ยเคลื่อนที่ถ่วงน้ำหนักบนข้อมูล ohlc ของฉันฉันมีเทียนประมาณ 134,000 ชิ้นที่มีสัญลักษณ์สำหรับให้ทำเช่นนั้น

  1. ตัวเลือกที่ 1 ทำได้ใน Python / Node ฯลฯ ฯลฯ
  2. ตัวเลือก 2 ทำใน SQL เอง!

อันไหนดีกว่า?

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

ความต้องการ

  • ถ้าฉันต้องคำนวณ WMA สำหรับเทียนทุกอันและเก็บไว้ฉันจะทำบน Python
  • แต่เนื่องจากฉันต้องการค่าสุดท้ายเท่านั้นSQL จึงเร็วกว่า Python มาก

เพื่อให้การสนับสนุนแก่คุณนี่คือรุ่น Python ที่ใช้ค่าเฉลี่ยเคลื่อนที่แบบถ่วงน้ำหนัก

WMA ทำผ่านรหัส

import psycopg2
import psycopg2.extras
from talib import func
import timeit
import numpy as np
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute('select distinct symbol from ohlc_900 order by symbol')
for symbol in cur.fetchall():
cur.execute('select c from ohlc_900 where symbol = %s order by ts', symbol)
ohlc = np.array(cur.fetchall(), dtype = ([('c', 'f8')]))
wma = func.WMA(ohlc['c'], 10)
# print(*symbol, wma[-1])
print(timeit.default_timer() - t0)
conn.close()

WMA ผ่าน SQL

"""
if the period is 10
then we need 9 previous candles or 15 x 9 = 135 mins on the interval department
we also need to start counting at row number - (count in that group - 10)
For example if AAPL had 134 coins and current row number was 125
weight at that row will be weight = 125 - (134 - 10) = 1
10 period WMA calculations
Row no Weight c
125 1
126 2
127 3
128 4
129 5
130 6
131 7
132 8
133 9
134 10
"""
query2 = """
WITH
condition(sym, maxts, cnt) as (
select symbol, max(ts), count(symbol) from ohlc_900 group by symbol
),
cte as (
select symbol, ts,
case when cnt >= 10 and ts >= maxts - interval '135 mins'
then (row_number() over (partition by symbol order by ts) - (cnt - 10)) * c
else null
end as weighted_close
from ohlc_900
INNER JOIN condition
ON symbol = sym
WINDOW
w as (partition by symbol order by ts rows between 9 preceding and current row)
)
select symbol, sum(weighted_close)/55 as wma
from cte
WHERE weighted_close is NOT NULL
GROUP by symbol ORDER BY symbol
"""
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute(query2)
# for i in cur.fetchall():
# print(*i)
print(timeit.default_timer() - t0)
conn.close()

เชื่อหรือไม่แบบสอบถามทำงานเร็วกว่า Pure Python ในการทำ WEVEED MOVING AVERAGE !!!ฉันไปทีละขั้นตอนในการเขียนแบบสอบถามที่ดังนั้นแขวนในที่นั่นและคุณจะทำอะไรได้ดี

ความเร็ว

0.42141127300055814 วินาที Python

0.23801879299935536 วินาทีของ SQL

ฉันมีระเบียน OHLC ปลอม 134,000 รายการในฐานข้อมูลของฉันแบ่งออกเป็น 1,000 หุ้นดังนั้นนี่คือตัวอย่างที่ SQL สามารถมีประสิทธิภาพสูงกว่าเซิร์ฟเวอร์แอปของคุณ


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