เหตุใด SELECT * จึงถือว่าเป็นอันตราย


256

ทำไมSELECT *การปฏิบัติที่ไม่ดี? รหัสจะน้อยลงหรือไม่ถ้าคุณเพิ่มคอลัมน์ใหม่ที่คุณต้องการ

ฉันเข้าใจว่าSELECT COUNT(*)เป็นปัญหาด้านประสิทธิภาพของฐานข้อมูลบางตัว แต่ถ้าคุณต้องการทุกคอลัมน์จริงๆ


30
SELECT COUNT(*)ความเป็นอยู่ที่ไม่ดีอย่างไม่น่าเชื่อเก่าและล้าสมัย สำหรับข้อมูลเกี่ยวกับSELECT *- ดู: stackoverflow.com/questions/1960036/…
OMG Ponies

8
SELECT COUNT(*)ให้คำตอบที่แตกต่างจากSELECT COUNT(SomeColumn)ถ้าคอลัมน์เป็นคอลัมน์ไม่เป็นโมฆะ และเครื่องมือเพิ่มประสิทธิภาพสามารถให้SELECT COUNT(*)การดูแลเป็นพิเศษ - และมักจะทำ โปรดทราบว่าWHERE EXISTS(SELECT * FROM SomeTable WHERE ...)จะได้รับการรักษากรณีพิเศษ
Jonathan Leffler

3
@Michael Mrozek จริงๆแล้วมันเป็นสิ่งที่ตรงกันข้ามของคำถาม ฉันกำลังถามว่ามันจะเป็นอันตรายไม่เคยเป็นอันตรายหรือไม่
Theodore R. Smith

1
@Bytecode Ninja: โดยเฉพาะ MySQL กับ MyISAM engine มีการเพิ่มประสิทธิภาพสำหรับ COUNT (*): mysqlperformanceblog.com/2007/04/10/count-vs-countcol
Piskvor ออกจากอาคาร

1
สำหรับ SQL Server โปรดดูsqlblog.com/blogs/aaron_bertrand/archive/2009/10/10//
Aaron Bertrand

คำตอบ:


312

มีเหตุผลสำคัญสามประการ:

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

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

  • ปัญหาการผูกเมื่อคุณเลือก * เป็นไปได้ที่จะดึงสองคอลัมน์ที่มีชื่อเดียวกันจากสองตารางที่แตกต่างกัน สิ่งนี้สามารถทำให้ผู้บริโภคข้อมูลของคุณเสียได้ ลองนึกภาพคิวรีที่รวมสองตารางซึ่งทั้งคู่มีคอลัมน์ชื่อ "ID" ผู้บริโภคจะรู้ได้อย่างไรว่าเป็นแบบไหน SELECT * ยังสามารถมองเห็นวิวสับสน (อย่างน้อยในบางรุ่น SQL Server) เมื่ออยู่ภายใต้การเปลี่ยนแปลงโครงสร้างตาราง - มุมมองที่ไม่ได้สร้างขึ้นมาใหม่และข้อมูลที่จะกลับมาสามารถเรื่องไร้สาระ และส่วนที่แย่ที่สุดคือคุณสามารถดูแลชื่อคอลัมน์ของคุณได้ทุกอย่างที่คุณต้องการ แต่ผู้ชายคนต่อไปที่เข้ามาอาจไม่มีทางรู้ว่าเขาต้องกังวลเกี่ยวกับการเพิ่มคอลัมน์ที่จะชนกับการพัฒนาของคุณแล้ว ชื่อ

แต่มันก็ไม่ได้แย่สำหรับ SELECT * ฉันใช้อย่างอิสระสำหรับกรณีการใช้งานเหล่านี้:

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

  • เมื่อ * หมายถึง "a row" ในกรณีการใช้งานต่อไปนี้ SELECT * นั้นใช้ได้และข่าวลือว่ามันเป็นตัวฆ่าประสิทธิภาพเป็นเพียงตำนานเมืองซึ่งอาจมีความถูกต้องเมื่อหลายปีก่อน แต่ไม่ใช่ตอนนี้:

    SELECT COUNT(*) FROM table;

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

    กันไปกับแบบสอบถามประเภทนี้:

    SELECT a.ID FROM TableA a
    WHERE EXISTS (
        SELECT *
        FROM TableB b
        WHERE b.ID = a.B_ID);

    ในฐานข้อมูลใด ๆ ที่คุ้มค่ากับเกลือ * เพียงแค่หมายถึง "a row" ไม่สำคัญว่าคุณใส่อะไรลงในคิวรี บางคนใช้ ID ของ b ในรายการ SELECT หรือพวกเขาจะใช้หมายเลข 1 แต่การประชุม IMO นั้นไร้สาระมาก สิ่งที่คุณหมายถึงคือ "นับแถว" และนั่นคือสิ่งที่ * หมายถึง เครื่องมือเพิ่มประสิทธิภาพข้อความค้นหาส่วนใหญ่มีความฉลาดพอที่จะรู้สิ่งนี้ (แม้ว่าจะซื่อสัตย์ แต่ฉันรู้ว่าเรื่องนี้เป็นจริงกับ SQL Server และ Oracle เท่านั้น)


17
การใช้ "SELECT id, name" น่าจะเป็น "SELECT *" เพื่อเลือกสองคอลัมน์ที่มีชื่อเดียวกันจากสองตารางที่แตกต่างกันเมื่อใช้การรวม คำนำหน้าด้วยชื่อตารางจะช่วยแก้ปัญหาในทั้งสองกรณี
Michał Tatarynowicz

1
ฉันรู้ว่านี่เก่ากว่า แต่มันเป็นสิ่งที่ดึงขึ้นมาได้ในขณะที่ googling ดังนั้นฉันจึงถาม "When * หมายถึง" a row "ในกรณีการใช้งานต่อไปนี้ SELECT * นั้นใช้ได้และข่าวลือว่ามันเป็นตัวทำลายประสิทธิภาพการทำงานเป็นเพียงตำนานเมือง ... "คุณมีการอ้างอิงที่นี่หรือไม่? เป็นคำสั่งนี้เนื่องจากฮาร์ดแวร์มีประสิทธิภาพมากขึ้น (ถ้าเป็นกรณีนี้ไม่ได้หมายความว่ามันไม่มีประสิทธิภาพเพียงแค่คุณมีโอกาสน้อยที่จะสังเกตเห็น) ฉันไม่ได้พยายามเดาครั้งที่สองฉันแค่สงสัยว่าข้อความนี้มาจากไหน
Jared

6
เท่าที่การอ้างอิงไปคุณสามารถตรวจสอบแผนแบบสอบถาม - พวกเขาเหมือนกันในกรณีที่คุณมี "*" ในแบบสอบถามย่อยเมื่อเทียบกับเมื่อคุณเลือกคอลัมน์ สิ่งเหล่านี้เหมือนกันเนื่องจากเครื่องมือเพิ่มประสิทธิภาพตามต้นทุน "รู้จัก" ความหมายคุณกำลังพูดถึงแถวที่ตรงตามเกณฑ์ - ไม่ใช่เรื่องของฮาร์ดแวร์หรือความเร็ว
Dave Markle

4
ข้อดีอีกอย่างของการใช้*คือในบางสถานการณ์มันสามารถใช้ประโยชน์จากระบบแคชของ MySQL ได้ดีขึ้น หากคุณใช้คิวรีที่คล้ายกันจำนวนมากselectซึ่งขอชื่อคอลัมน์ที่แตกต่างกัน ( select A where X,, select B where X... ) โดยใช้ a select * where Xจะทำให้แคชสามารถจัดการคิวรีที่ใหญ่กว่าซึ่งอาจทำให้ประสิทธิภาพเพิ่มขึ้นอย่างมาก มันเป็นสถานการณ์เฉพาะแอปพลิเคชัน แต่ก็ควรคำนึงถึง
เบ็นดี

2
8 ปีขึ้นไป แต่ต้องการเพิ่มประเด็นเกี่ยวกับความกำกวมที่ไม่ได้กล่าวถึง ทำงานกับ 200+ ตารางในฐานข้อมูลและมีการผสมผสานของแบบแผนการตั้งชื่อ เมื่อตรวจสอบรหัสที่ติดต่อกับผลการสอบถามSELECT *นักพัฒนากองกำลังที่จะมองไปที่โต๊ะสคี (s) มีส่วนร่วมในการกำหนดคอลัมน์ที่ได้รับผลกระทบ / ใช้ได้เช่นภายในหรือforeach serializeงานที่ต้องดู schemas ซ้ำ ๆ เพื่อติดตามสิ่งที่เกิดขึ้นย่อมเพิ่มเวลาโดยรวมที่เกี่ยวข้องทั้งในการดีบักและพัฒนารหัสที่เกี่ยวข้อง
fyrye

91

อักขระเครื่องหมายดอกจัน "*" ในคำสั่ง SELECT จะเป็นการย่อสำหรับคอลัมน์ทั้งหมดในตารางที่เกี่ยวข้องกับแบบสอบถาม

ประสิทธิภาพ

การ*จดชวเลขทำได้ช้าลงเพราะ:

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

ซ่อมบำรุง

เมื่อใช้SELECT *:

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

ออกแบบ

SELECT *เป็นรูปแบบการต่อต้าน :

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

เมื่อใดควรใช้ "SELECT *"

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

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


20

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

รหัสจะน้อยลงหรือไม่ถ้าคุณเพิ่มคอลัมน์ใหม่ที่คุณต้องการ

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


21
โดยเฉพาะอย่างยิ่งหากคอลัมน์ใหม่นั้นเป็น BLOB สามเมกะไบต์
Matti Virkkunen

2
@Matti - แต่หวังว่าพวกเขาจะคิดมากกว่า"เฮ้ปล่อยคอลัมน์ BLOB ขนาดใหญ่มาไว้บนโต๊ะนี้!" . (ใช่คนโง่หวังว่าฉันจะรู้ แต่ผู้ชายในฝันไม่ได้?)
ChaosPandion

5
ประสิทธิภาพการทำงานเป็นแง่มุมหนึ่ง แต่บ่อยครั้งที่ยังมีแง่มุมที่ถูกต้อง: รูปร่างของผลลัพธ์ที่คาดการณ์ด้วย*สามารถเปลี่ยนแปลงได้โดยไม่คาดคิดและสิ่งนี้สามารถสร้างความหายนะในแอปพลิเคชันเอง: คอลัมน์อ้างอิงตามลำดับ (เช่น sqldatareader.getstring (2))ที่แตกต่างกันคอลัมน์ใด ๆ ที่INSERT ... SELECT *จะทำลายและอื่น ๆ และอื่น ๆ
Remus Rusanu

2
@chaos: การใส่ blobs ลงบนโต๊ะจะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงานของคุณมากนัก ... เว้นแต่คุณจะเลือก SELECT * ... ;-)
เดฟมาร์เคิล

2
คุณไม่ควรกังวลเกี่ยวกับประสิทธิภาพจนกว่าจะเกิดปัญหาจริง และยังSELECT *ไม่ได้เป็นเรื่องของการบันทึกตัวละครน้อย มันเป็นเรื่องของการประหยัดเวลาในการดีบักเพราะมันง่ายที่จะลืมระบุคอลัมน์ที่เพิ่มใหม่
Lewis

4

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


"อาจจะทำให้ได้อย่างปลอดภัยได้รับการอ้างอิงโดยดัชนีตัวเลข" แต่ใครจะเพียงพอโง่เคยลองและอ้างอิงคอลัมน์โดยดัชนีตัวเลขแทนมันชื่อ !? นี่เป็นรูปแบบการต่อต้านที่แย่กว่าการใช้ select * ในมุมมอง
MGOwen

@MGOwen: การใช้select *แล้วใช้คอลัมน์โดยดัชนีจะน่ากลัว แต่การใช้select X, Y, Zหรือselect A,B,Cจากนั้นส่งผ่านเครื่องอ่านข้อมูลไปยังโค้ดซึ่งคาดว่าจะทำอะไรกับข้อมูลในคอลัมน์ 0, 1 และ 2 ดูเหมือนจะเป็นวิธีที่เหมาะสมที่สุดในการ อนุญาตให้โค้ดเดียวกันดำเนินการกับ X, Y, Z หรือ A, B, C โปรดทราบว่าดัชนีของคอลัมน์จะขึ้นอยู่กับที่ตั้งของพวกเขาภายในคำสั่ง SELECT แทนที่จะเป็นลำดับในฐานข้อมูล
supercat

3

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


1
ดังนั้นการตั้งชื่อคอลัมน์จะช่วยได้อย่างไร ใน SQL Server แบบสอบถามที่มีอยู่ซึ่งฝังอยู่ในรหัสหรือ SP จะไม่บ่นจนกว่าจะมีการเรียกใช้แม้ว่าคุณจะตั้งชื่อคอลัมน์แล้วก็ตาม ใหม่จะล้มเหลวเมื่อคุณทดสอบพวกเขา แต่เวลามากมายที่คุณต้องไปหา SPs รับผลกระทบจากการเปลี่ยนแปลงตาราง คุณหมายถึงสถานการณ์แบบใดที่อ้างถึงในเวลาออกแบบ?
ChrisA

3

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

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


3

คิดว่ามันเป็นการลดการเชื่อมต่อระหว่างแอพและฐานข้อมูล

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


3

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

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

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

หากคุณระบุฟิลด์ที่คุณต้องการในผลลัพธ์คุณจะปลอดภัยจากโอเวอร์โฟลว์ประเภทนี้



2

การอ้างอิงที่นำมาจากบทความนี้

ไม่เคยไปกับ "SELECT *"

ฉันพบเหตุผลเดียวที่จะใช้ "SELECT *"

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


1

โดยทั่วไปคุณต้องปรับให้เหมาะกับผลลัพธ์ของคุณ SELECT * ...โครงสร้างข้อมูลของคุณ โดยไม่ต้องระบุว่าจะเรียงลำดับผลลัพธ์ใดก็อาจเป็นเรื่องยากที่จะจัดเรียงทุกอย่างให้เหมาะสม

วิธีนี้คุณสามารถเพิ่มเขตข้อมูลลงในตารางของคุณ (แม้ในตรงกลางของพวกเขา) ด้วยเหตุผลต่าง ๆ โดยไม่ทำลายรหัสการเข้าถึง sql ทั่วทั้งแอปพลิเคชัน


1

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

นอกจากนี้ยังง่ายต่อการดูเมื่อดูแบบสอบถามว่ามีการโหลดคอลัมน์ใดโดยไม่ต้องค้นหาสิ่งที่อยู่ในตาราง

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

นี่ก็เป็นเหตุผลแบบเดียวกันถ้าคุณทำแบบนั้นINSERTคุณควรระบุคอลัมน์เสมอ


1

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

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


1

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

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


1

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

ตัวอย่างเช่น: BigQuery :

การกำหนดราคาแบบสอบถาม

การกำหนดราคาแบบสอบถามหมายถึงต้นทุนในการใช้คำสั่ง SQL และฟังก์ชั่นที่ผู้ใช้กำหนด BigQuery เรียกเก็บเงินจากการค้นหาโดยใช้หนึ่งเมตริก: จำนวนไบต์ที่ประมวลผล

และการควบคุมการฉาย - หลีกเลี่ยงการเลือก * :

วิธีปฏิบัติที่ดีที่สุด: ควบคุมการฉาย - ค้นหาเฉพาะคอลัมน์ที่คุณต้องการ

การฉายหมายถึงจำนวนคอลัมน์ที่แบบสอบถามของคุณอ่าน การคาดคอลัมน์ส่วนเกินจะเกิด I ​​/ O เพิ่มเติมและสูญเสียไป (การเขียนผลลัพธ์)

การใช้ SELECT * เป็นวิธีสอบถามข้อมูลที่แพงที่สุด เมื่อคุณใช้ SELECT *, BigQuery ทำการสแกนแบบเต็มของทุกคอลัมน์ในตาราง


0

ทำความเข้าใจความต้องการของคุณก่อนที่จะออกแบบสคีมา (ถ้าเป็นไปได้)

เรียนรู้เกี่ยวกับข้อมูล 1) การจัดทำดัชนี 2) ประเภทของที่เก็บข้อมูลที่ใช้ 3) เครื่องมือหรือคุณลักษณะของผู้ขาย เช่น ... แคชความสามารถในหน่วยความจำ 4) ประเภทข้อมูล 5) ขนาดของตาราง 6) ความถี่ของแบบสอบถาม 7) เวิร์กโหลดที่เกี่ยวข้องหากทรัพยากรถูกแชร์ 8) การทดสอบ

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

สมมติว่าไม่มีวิธีแก้ปัญหาอื่น คุณสามารถพิจารณาสิ่งต่อไปนี้ มีวิธีแก้ไขปัญหาอยู่เสมอ

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

2) ประเภทของการจัดเก็บ เช่น: ถ้าคุณใช้ SSD, ดิสก์หรือหน่วยความจำ I / O ครั้งและโหลดบนระบบ / cpu จะแตกต่างกันไป

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

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

5) ขนาดของตาราง / ข้อมูล select '*' เป็นเรื่องปกติกับตารางเล็ก ๆ โดยทั่วไปจะพอดีกับหน่วยความจำและเวลาตอบสนองรวดเร็ว อีกครั้ง .... ตรวจสอบความต้องการของคุณ วางแผนสำหรับฟีเจอร์คืบ; วางแผนความต้องการในปัจจุบันและอนาคตที่เป็นไปได้เสมอ

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

7) ปริมาณงานที่เกี่ยวข้อง ทำความเข้าใจวิธีการใช้ทรัพยากร เครือข่าย / ระบบ / ฐานข้อมูล / ตาราง / แอปพลิเคชันทุ่มเทหรือแชร์หรือไม่ ใครคือผู้มีส่วนได้เสีย? นี่สำหรับการผลิตการพัฒนาหรือ QA หรือไม่? นี่เป็น "การแก้ไขด่วน" ชั่วคราวหรือไม่ คุณทดสอบสถานการณ์แล้วหรือยัง? คุณจะประหลาดใจกับปัญหาที่มีอยู่บนฮาร์ดแวร์ปัจจุบันในปัจจุบัน (ใช่ประสิทธิภาพเร็ว ... แต่การออกแบบ / ประสิทธิภาพยังลดลง) ระบบจำเป็นต้องมีการค้นหา 10K ต่อวินาทีหรือ 5-10 แบบสอบถามต่อวินาที เป็นเซิร์ฟเวอร์ฐานข้อมูลเฉพาะหรือทำแอปพลิเคชันอื่น ๆ ตรวจสอบดำเนินการบนทรัพยากรที่ใช้ร่วมกัน แอปพลิเคชั่น / ภาษาบางอย่าง; O / S จะใช้หน่วยความจำ 100% ทำให้เกิดอาการ / ปัญหาต่าง ๆ

8) การทดสอบ: ทดสอบทฤษฎีของคุณและทำความเข้าใจให้มากที่สุด ปัญหา '*' ที่คุณเลือกอาจเป็นเรื่องใหญ่หรืออาจเป็นสิ่งที่คุณไม่ต้องกังวล

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