เลือก * เทียบกับคอลัมน์เลือก


124

ถ้าฉันต้องการเพียง 2/3 คอลัมน์และฉันสอบถามSELECT *แทนที่จะให้คอลัมน์เหล่านั้นในคิวรีที่เลือกมีการลดประสิทธิภาพการทำงานเกี่ยวกับ I / O หรือหน่วยความจำมาก / น้อยหรือไม่

ค่าโสหุ้ยเครือข่ายอาจปรากฏขึ้นหากฉันเลือก * โดยไม่จำเป็น

แต่ในการดำเนินการที่เลือกเอ็นจินฐานข้อมูลจะดึงอะตอมทูเพิลจากดิสก์เสมอหรือดึงเฉพาะคอลัมน์ที่ร้องขอในการดำเนินการเลือก

ถ้ามันดึงทูเปิลเสมอค่าใช้จ่าย I / O จะเท่ากัน

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

ดังนั้นหากเป็นกรณีนี้ให้เลือก someColumn จะมีหน่วยความจำเหนือศีรษะมากกว่าที่เลือก *


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

10
นอกจากนี้ใน PostgreSQL ถ้าคุณพูดว่าCREATE VIEW foo_view AS SELECT * FROM foo;ให้เพิ่มคอลัมน์ในตาราง foo ในภายหลังคอลัมน์เหล่านั้นจะไม่แสดงใน foo_view โดยอัตโนมัติตามที่คาดไว้ กล่าวอีกนัยหนึ่ง*ในบริบทนี้จะขยายเพียงครั้งเดียว (ในเวลาสร้างมุมมอง) ไม่ใช่ต่อ SELECT เนื่องจากภาวะแทรกซ้อนที่เกิดจาก ALTER TABLE ฉันจะบอกว่า (ในทางปฏิบัติ) *ถือว่าเป็นอันตราย
Joey Adams

@JoeyAdams - ไม่ใช่แค่ PostgresQL เท่านั้น แต่ยังเป็นพฤติกรรมของ Oracle ด้วย
APC

1
@ OMG Ponies: ฉันไม่ทราบว่ามีการโพสต์ที่คล้ายกัน อย่างไรก็ตามสิ่งเหล่านี้ไม่ใช่ตัวจำลองจริงๆ @ หมิ่นพระบรมเดชานุภาพ: ฉันกำลังพูดถึง Generic RDBMS ไม่เกี่ยวกับผู้ขายรายใดรายหนึ่ง @Joey Adams: อืมฉันรู้ว่า * ไม่ปลอดภัย เพียงแค่ต้องการพูดคุยเกี่ยวกับปัญหาด้านประสิทธิภาพ
Neel Basu

3
ความเป็นไปได้ที่ซ้ำกันของเหตุใด SELECT * จึงถือว่าเป็นอันตราย
Aaron Bertrand

คำตอบ:


31

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

มันดึงทูเพิลเสมอเพราะ (ในผู้ขาย RDBMS ทุกรายที่ฉันคุ้นเคย) โครงสร้างหน่วยความจำบนดิสก์สำหรับทุกอย่าง (รวมถึงข้อมูลตาราง) จะขึ้นอยู่กับI / O Pages ที่กำหนดไว้ (ใน SQL Server เช่นแต่ละเพจคือ 8 กิโลไบต์). และทุก I / O อ่านหรือเขียนโดย Page .. กล่าวคือทุกการเขียนหรือการอ่านคือหน้าข้อมูลที่สมบูรณ์

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

ข้อยกเว้น ที่เดียวที่Select *OK อยู่ในแบบสอบถามย่อยหลังอนุประโยคExistsหรือเพรNot Existsดิเคตดังใน:

   Select colA, colB
   From table1 t1
   Where Exists (Select * From Table2
                 Where column = t1.colA)

แก้ไข: เพื่อแสดงความคิดเห็นของ @Mike Sherer ใช่มันเป็นความจริงทั้งในทางเทคนิคพร้อมคำจำกัดความสำหรับกรณีพิเศษของคุณและความสวยงาม ประการแรกแม้ว่าชุดของคอลัมน์ที่ร้องขอจะเป็นชุดย่อยของคอลัมน์ที่เก็บไว้ในดัชนีบางตัว แต่ตัวประมวลผลการสืบค้นจะต้องดึงข้อมูลทุกคอลัมน์ที่เก็บไว้ในดัชนีนั้นไม่ใช่เฉพาะคอลัมน์ที่ร้องขอด้วยเหตุผลเดียวกัน - ต้องทำ I / O ทั้งหมดใน เพจและข้อมูลดัชนีจะถูกเก็บไว้ใน IO Pages เช่นเดียวกับข้อมูลตาราง ดังนั้นหากคุณกำหนด "ทูเพิล" สำหรับหน้าดัชนีเป็นชุดของคอลัมน์ที่เก็บไว้ในดัชนีคำสั่งนั้นจะยังคงเป็นจริง
และคำสั่งนั้นเป็นจริงอย่างสวยงามเพราะประเด็นคือมันดึงข้อมูลตามสิ่งที่เก็บไว้ในหน้า I / O ไม่ใช่สิ่งที่คุณขอและนี่เป็นความจริงไม่ว่าคุณจะเข้าถึง I / O Page หรือดัชนีของตารางฐาน หน้า I / O

สำหรับเหตุผลอื่น ๆ ที่จะไม่ใช้Select *โปรดดู เหตุใดจึงSELECT *ถือว่าเป็นอันตราย :


"มันดึงทูเปิลเสมอ" แน่ใจหรือ? อืมโอเคฉันพูดถูก หากเป็นเช่นselect *นั้นจะมีค่าใช้จ่ายหน่วยความจำน้อยกว่าselect columnแต่โอเวอร์เฮดI / O เดียวกัน ดังนั้นหากเราปล่อยให้เครือข่ายอยู่เหนือศีรษะ select *ถ้าค่าใช้จ่ายน้อยกว่าselect column
Neel Basu

10
นี่ไม่เป็นความจริง. ตัวอย่างหนึ่งที่อยู่เหนือหัวของฉันคือเมื่อคุณต้องการเฉพาะค่าของคอลัมน์ที่จัดทำดัชนีใน MySQL (ตัวอย่างเช่นเพื่อตรวจสอบการมีอยู่ของแถว) และคุณกำลังใช้โปรแกรมจัดเก็บข้อมูล MyISAM มันจะดึงข้อมูลจาก MYI ซึ่งอาจอยู่ในหน่วยความจำและไม่ได้ไปที่ดิสก์!
Mike Sherov

ถ้าชุดทูเปิลที่ร้องขออยู่ในหน่วยความจำจะไม่มี I / O แต่เป็นกรณีพิเศษ ฤดูร้อนคืออะไร ถ้าฉันเลือกคอลัมน์ที่จัดทำดัชนีแล้วทูเปิลทั้งหมดจะไม่ถูกอ่าน? มิฉะนั้นจะอ่าน tuple ทั้งหมด?
Neel Basu

ฉันไม่แน่ใจว่า MySql ทำแคชอย่างไร แต่ใน SQL Server และใน Oracle แม้ว่าข้อมูลจะอยู่ในแคชในหน่วยความจำ แต่ก็ยังเข้าถึงข้อมูลได้โดยใช้โครงสร้างหน้าเดียวกับที่จะเข้าถึงจากดิสก์ หมายความว่าจะต้องใช้หน่วยความจำ I / O หนึ่งหน้าข้อมูล ... เหมือนกับที่ต้องการจากดิสก์ (ยกเว้น memory I / Os เร็วกว่า Disk I / Os แน่นอน) นั่นคือเป้าหมายของการออกแบบแคชเพื่อให้กระบวนการเข้าถึงเป็นอิสระโดยสิ้นเชิงกับตำแหน่งของข้อมูล
Charles Bretana

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

111

มีสาเหตุหลายประการที่คุณไม่ควรใช้SELECT *ในรหัสการผลิต:

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

  • หากคุณต้องการเพียง 2/3 ของคอลัมน์คุณกำลังเลือกข้อมูลมากเกินไปถึง 1/3 ซึ่งจำเป็นต้องดึงข้อมูลจากดิสก์และส่งผ่านเครือข่าย

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

  • ใน SQL Server (ไม่แน่ใจเกี่ยวกับฐานข้อมูลอื่น ๆ ) หากคุณต้องการชุดย่อยของคอลัมน์มีโอกาสเสมอที่ดัชนีที่ไม่ใช่คลัสเตอร์อาจครอบคลุมคำขอนั้น (มีคอลัมน์ทั้งหมดที่จำเป็น) ด้วย a SELECT *คุณจะยอมแพ้กับความเป็นไปได้นั้นทันทีตั้งแต่เริ่มต้น ในกรณีนี้ข้อมูลจะถูกดึงมาจากหน้าดัชนี (หากมีคอลัมน์ที่จำเป็นทั้งหมด) ดังนั้นดิสก์ I / O และค่าใช้จ่ายหน่วยความจำจะน้อยกว่ามากเมื่อเทียบกับการทำSELECT *....แบบสอบถาม

ใช่ต้องใช้เวลาพิมพ์มากกว่าเล็กน้อยในตอนแรก (เครื่องมือเช่นSQL Promptสำหรับ SQL Server จะช่วยคุณได้) แต่นี่เป็นกรณีหนึ่งที่มีกฎโดยไม่มีข้อยกเว้น: อย่าใช้ SELECT * ในรหัสการผลิตของคุณ เคย.


13
ในขณะที่เห็นด้วยกับคุณในทางปฏิบัติคุณถูกต้องอย่างแน่นอนในทุกกรณีเมื่อดึงข้อมูลคอลัมน์จากตารางตามที่อยู่ของคำถามนี้) การให้ความสำคัญกับ EVER อย่างไรก็ตามทำให้ฉันชี้ให้เห็นว่ากฎนี้ไม่ใช่กฎทั่วไปสำหรับแบบสอบถาม SQL ทั้งหมด .. โดยเฉพาะการใช้ในแบบสอบถามย่อยหลังจากเพรดิเคต EXISTS (เช่นเดียวกับWhere Exists (Select * From ...) การใช้งานSelect *นั้นไม่มีปัญหาและในบางแวดวงถือเป็นแนวทางปฏิบัติที่ดีที่สุด
Charles Bretana

3
@Charles Bretana: ใช่IF EXISTS(SELECT *...เป็นกรณีพิเศษ - เนื่องจากไม่มีการดึงข้อมูลจริง ๆ แต่เป็นเพียงการตรวจสอบการมีอยู่เท่านั้น SELECT * ไม่ใช่ปัญหาที่นั่น ...
marc_s

1
แล้วถ้าฉันกำลังพัฒนา API ที่ทำให้สามารถดึงข้อมูลจากตารางของฉันได้ เนื่องจากฉันไม่รู้ว่าผู้ใช้สนใจข้อมูลใดฉันจึงคิดว่า SELECT * จะยอมรับได้หรือไม่?
Simon Bengtsson

1
@SimonBengtsson: ฉันยังคงโต้แย้งเรื่องนี้ - สมมติว่าคุณมีข้อมูล "การดูแลระบบ" ในคอลัมน์เฉพาะในตารางของคุณที่คุณไม่ต้องการเปิดเผยต่อลูกค้า? ฉันจะระบุรายการคอลัมน์ที่จะดึงอย่างชัดเจนเสมอ
marc_s

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

21

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

[แก้ไข]: หมายถึงการเข้าถึง โง่สมองยังตื่นเลย


3
+1 สำหรับกรณี edge ที่ฉันเชื่อว่ามีไม่มากนักที่จะนึกถึงในตอนแรก - ดัชนีในฝั่งไคลเอนต์และคอลัมน์ที่เพิ่ม / เปลี่ยนแปลง
Tomas Aschan

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

11
เห็นสิ่งนี้มานานแล้วโปรแกรมเมอร์รุ่นเยาว์เลือก * จากตารางและตั้งสมมติฐานเกี่ยวกับลำดับคอลัมน์ รหัสทั้งหมดของเขาพังทันทีที่มีคนอื่นเปลี่ยนโต๊ะ เรามีอะไรสนุก ๆ
Paul McKenzie

7
อาจเป็นความคิดที่ดีที่จะใช้ลำดับคอลัมน์โดยทั่วไปเพียงเพื่อประโยชน์ในการอ่านโค้ดเท่านั้นซึ่งไม่ดีเลยที่จะใช้SELECT *กับมัน
หมิ่นพระบรมเดชานุภาพ

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

7

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

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


6

นี้ทันทีทำให้ฉันคิดว่าของตารางผมใช้ที่มีคอลัมน์ชนิดหนึ่งblob; โดยปกติจะมีภาพ JPEG ขนาดไม่กี่Mbวินาที

ไม่จำเป็นต้องบอกว่าฉันไม่ได้SELECTคอลัมน์นั้นเว้นแต่ฉันต้องการมันจริงๆ การมีข้อมูลนั้นลอยอยู่รอบ ๆ โดยเฉพาะอย่างยิ่งเมื่อฉันเลือกหลายแถว - เป็นเรื่องยุ่งยาก

อย่างไรก็ตามฉันยอมรับว่าโดยปกติแล้วฉันมักจะค้นหาคอลัมน์ทั้งหมดในตาราง


20
คอลัมน์ LOB เป็นตัวอย่างที่ฉันชอบเสมอเกี่ยวกับอันตรายของ SELECT * ฉันกำลังจะโหวตให้คุณจนกว่าฉันจะอ่านย่อหน้าที่สาม Tsk, tsk. จะเกิดอะไรขึ้นถ้านักพัฒนารายอื่นเพิ่ม BLOB ลงในตารางซึ่งขณะนี้ไม่มีคอลัมน์ดังกล่าว
APC

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

1
@ user256007 ใช่แม้ไม่มี BLOB ... BLOB แค่แสดงตัวอย่างที่รุนแรง ตรวจสอบคำตอบของฉันที่มีต่อ Charles มีหลายครั้งที่การเลือกคอลัมน์เฉพาะสามารถช่วยให้คุณสามารถดึงข้อมูลจากหน่วยความจำได้โดยไม่ต้องใช้ดิสก์!
Mike Sherov

1
@ ริชาร์ดฉันคิดว่ามันยอดเยี่ยมสำหรับการเพิ่มประสิทธิภาพการทำงานของฐานข้อมูลไม่ใช่ประเด็นหลักของคุณซึ่งเป็น 99% ของเวลา เช่นเดียวกับกรอบงานส่วนใหญ่พวกเขามักจะพูดถึงสิ่งต่าง ๆ เพื่อให้สามารถพัฒนาได้เร็วขึ้นในขณะที่เสียสละประสิทธิภาพที่แท้จริง ดังที่ Knuth กล่าวว่า: "การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากเหง้าของความชั่วร้ายทั้งหมด" เมื่อคุณไปถึงจุดที่คุณต้องกังวลเกี่ยวกับประสิทธิภาพของคอลัมน์ที่เลือกเทียบกับเลือก * (ถาม Twitter เกี่ยวกับ RoR) คุณสามารถกังวลเกี่ยวกับเรื่องนี้และปรับให้เหมาะสมได้ หากเฟรมเวิร์กไม่แข็งแกร่งพอที่จะรองรับสิ่งนั้นฉันจะบอกว่าคุณกำลังใช้เฟรมเวิร์กที่ไม่ถูกต้อง
Mike Sherov

1
@ user256007 - กฎทั่วไปคือ "อย่าใช้ SELECT *" คำตอบจาก marc_s มีเหตุผลทั้งหมดว่าทำไมจึงเป็นเช่นนั้น
APC

6

ในระหว่างการเลือก SQL DB จะอ้างถึงข้อมูลเมตาสำหรับตารางเสมอไม่ว่าจะเป็น SELECT * สำหรับ SELECT a, b, c ... ทำไม? นั่นคือที่ที่ข้อมูลเกี่ยวกับโครงสร้างและรูปแบบของตารางบนระบบอยู่

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

ตอนนี้เห็นได้ชัดว่าข้อมูลเมตา DB ถูกแคชไว้ในระบบ แต่ยังคงต้องดำเนินการประมวลผล

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

ครั้งเดียวที่การประมวลผลนี้ไม่เสร็จสิ้นคือเมื่อฐานข้อมูลกำลังใช้แบบสอบถามที่คอมไพล์ไว้ล่วงหน้าหรือแคชแบบสอบถามก่อนหน้า นี่คืออาร์กิวเมนต์สำหรับการใช้พารามิเตอร์การรวมแทน SQL ตามตัวอักษร "SELECT * FROM TABLE WHERE key = 1" เป็นคำค้นหาที่แตกต่างจาก "SELECT * FROM TABLE WHERE key =?" และ "1" ถูกผูกไว้กับการโทร

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

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

ถ้าคุณมี:

CREATE TABLE customer (
    id INTEGER NOT NULL PRIMARY KEY,
    name VARCHAR(150) NOT NULL,
    city VARCHAR(30),
    state VARCHAR(30),
    zip VARCHAR(10));

CREATE INDEX k1_customer ON customer(id, name);

จากนั้นถ้าคุณทำ "SELECT id, name FROM customer WHERE id = 1" เป็นไปได้มากที่ DB ของคุณจะดึงข้อมูลนี้จากดัชนีแทนที่จะมาจากตาราง

ทำไม? มีแนวโน้มว่าจะใช้ดัชนีเพื่อตอบสนองการสืบค้น (เทียบกับการสแกนตาราง) และแม้ว่า "ชื่อ" จะไม่ได้ใช้ในส่วนคำสั่งที่ใด แต่ดัชนีนั้นก็ยังคงเป็นตัวเลือกที่ดีที่สุดสำหรับการสืบค้น

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

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

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


ฉันจะลดคะแนนคำตอบของคุณเพียงเพราะคุณใช้ NOT NULL ร่วมกับ PRIMARY KEY มีเหตุผลที่ดีที่คุณจะเขียนแบบนี้หรือไม่?
ผู้เรียน

4

ฉันคิดว่าไม่มีคำตอบที่แน่นอนสำหรับคำถามของคุณเนื่องจากคุณได้ไตร่ตรองประสิทธิภาพและความสะดวกในการดูแลรักษาแอปของคุณ Select columnมีประสิทธิภาพมากกว่าselect *แต่ถ้าคุณกำลังพัฒนาระบบวัตถุที่มุ่งเน้นคุณจะชอบการใช้งานobject.propertiesและคุณสามารถต้องการคุณสมบัติในส่วนใดก็ได้ของแอพคุณจะต้องเขียนวิธีการเพิ่มเติมเพื่อรับคุณสมบัติในสถานการณ์พิเศษหากคุณไม่ทำ ใช้select *และเติมข้อมูลคุณสมบัติทั้งหมด แอปของคุณต้องมีประสิทธิภาพที่ดีในการใช้งานselect *และในบางกรณีคุณจะต้องใช้คอลัมน์เลือกเพื่อปรับปรุงประสิทธิภาพ จากนั้นคุณจะมีสิ่งที่ดีกว่าของสองโลกสิ่งอำนวยความสะดวกในการเขียนและบำรุงรักษาแอพและประสิทธิภาพเมื่อคุณต้องการประสิทธิภาพ


4

คำตอบที่ยอมรับที่นี่ไม่ถูกต้อง ฉันเจอสิ่งนี้เมื่อคำถามอื่นถูกปิดเนื่องจากซ้ำกัน (ในขณะที่ฉันยังคงเขียนคำตอบ - grr - ดังนั้น SQL ด้านล่างอ้างอิงคำถามอื่น)

คุณควรใช้แอตทริบิวต์ SELECT แอตทริบิวต์ .... ไม่ใช่ SELECT *

ปัญหาด้านประสิทธิภาพเป็นหลัก

เลือกชื่อจากผู้ใช้ WHERE name = 'John';

ไม่ใช่ตัวอย่างที่มีประโยชน์มากนัก. พิจารณาแทน:

SELECT telephone FROM users WHERE name='John';

หากมีดัชนี (ชื่อโทรศัพท์) จะสามารถแก้ไขแบบสอบถามได้โดยไม่ต้องค้นหาค่าที่เกี่ยวข้องจากตาราง - มีดัชนีครอบคลุม

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

นอกจากนี้ยังอาจทำให้เกิดปัญหาในการทำงานหากไคลเอนต์ดึงข้อมูลเป็นอาร์เรย์ที่แจกแจง (เช่น mysql_fetch_array ของ PHP ($ x, MYSQL_NUM)) บางทีเมื่อรหัสถูกเขียนว่า 'โทรศัพท์' เป็นคอลัมน์ที่สามที่จะส่งคืนโดย SELECT * แต่แล้วก็มีคนเข้ามาและตัดสินใจเพิ่มที่อยู่อีเมลลงในตารางโดยวางไว้ก่อน "โทรศัพท์" ตอนนี้ช่องที่ต้องการจะเลื่อนไปที่คอลัมน์ที่ 4


2

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

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

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

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

แต่โปรดทราบว่าฉันใช้ SELECT * โดยปกติจะใช้กับเลเยอร์ที่เป็นนามธรรมแทนที่จะเป็นตารางฐาน


2

อ้างอิงจากบทความนี้:

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

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


0

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

หากคุณไม่คุ้นเคยกับการจัดเก็บข้อมูลเชิงคอลัมน์การนำไปใช้งานหนึ่งสำหรับ Postgres มาจาก Citus Data อีกรายการหนึ่งคือ Greenplum Paraccel อีกอันหนึ่ง (พูดแบบหลวม ๆ ) คือ Amazon Redshift สำหรับ MySQL มี Infobright ซึ่งเป็น InfiniDB ที่ใกล้จะหมดอายุแล้ว ข้อเสนอเชิงพาณิชย์อื่น ๆ ได้แก่ Vertica จาก HP, Sybase IQ, Teradata ...


-1
select * from table1 INTERSECT  select * from table2

เท่ากัน

select distinct t1 from table1 where Exists (select t2 from table2 where table1.t1 = t2 )

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