เหตุใด“ เลือก * จากตาราง” จึงถือว่าไม่เหมาะสม


96

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

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


1
ฉันจะบอกว่ามันจะเกิดอะไรขึ้นถ้าเนื้อหาตารางเปลี่ยนแปลง? การเพิ่ม / ลบคอลัมน์? คุณยังคงเลือก * .. ดังนั้นคุณจะพลาดสิ่งต่าง ๆ หรือดึงข้อมูลกลับมามากกว่าที่คุณต้องการ
เจเอฟมัน

2
@JFit นั่นเป็นส่วนหนึ่งของมัน แต่อยู่ไกลจากเรื่องราวทั้งหมด
jwenting

8
เหตุผลที่ดีที่ SO - stackoverflow.com/questions/3180375/select-vs-select-column
Bratch


@gnat คำถามอาจถูกพิจารณาว่าซ้ำซ้อนกับคำถามปิดได้หรือไม่ (เช่นเนื่องจากคนที่ปิดไม่เหมาะในตอนแรก)
gbjbaanb

คำตอบ:


67

คิดเกี่ยวกับสิ่งที่คุณได้รับกลับมาและวิธีที่คุณผูกกับตัวแปรในรหัสของคุณ

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

การใช้ select * เมื่อคุณพิมพ์คำสั่งด้วยมือนั้นไม่ได้เกิดขึ้นเมื่อคุณกำลังเขียนคิวรีสำหรับรหัส


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

21
@ jwenting จริงเหรอ? เรื่องประสิทธิภาพมากกว่าความถูกต้อง? อย่างไรก็ตามฉันไม่เห็นว่า "select *" ทำงานได้ดีกว่าการเลือกเฉพาะคอลัมน์ที่คุณต้องการ
gbjbaanb

9
@Bratch ในสภาพแวดล้อมการใช้งานจริงคุณอาจมีแอพพลิเคชั่นหลายร้อยรายการที่ใช้ตารางเดียวกันและไม่มีวิธีที่เป็นไปได้ที่แอพพลิเคชั่นทั้งหมดจะสามารถดูแลรักษาได้อย่างเหมาะสม คุณถูกต้องในความรู้สึก แต่ในทางปฏิบัติข้อโต้แย้งล้มเหลวเพียงเพราะความเป็นจริงของการทำงานใน copmanies การเปลี่ยนแปลงโครงสร้างของตารางที่ใช้งานจะเกิดขึ้นตลอดเวลา
user1068

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

11
@gbjbaanb จากนั้นเข้าถึงคอลัมน์ตามชื่อ สิ่งใดจะโง่อย่างเห็นได้ชัดเว้นแต่คุณจะระบุลำดับคอลัมน์ในแบบสอบถาม
immibis

179

การเปลี่ยนแปลงแบบแผน

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

ไม่ว่าจะด้วยวิธีใดการเปลี่ยนแปลงสคีมาอาจทำให้เกิดปัญหากับการแยกข้อมูล

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

ข้อมูลค่าใช้จ่าย

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

เกี่ยวข้องกับการเปลี่ยนแปลงสกีมา varchar นั้นอาจไม่มีอยู่เมื่อคุณสร้างตารางครั้งแรก แต่ตอนนี้มีอยู่ที่นั่น

ความล้มเหลวในการถ่ายทอดเจตนา

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


ให้ดูที่ SQL fiddles ที่สำรวจschemaเหล่านั้นเปลี่ยนแปลงไปอีกเล็กน้อย

ก่อนอื่นฐานข้อมูลเริ่มต้น: http://sqlfiddle.com/#!2/a67dd/1

DDL:

create table one (oneid int, data int, twoid int);
create table two (twoid int, other int);

insert into one values (1, 42, 2);
insert into two values (2, 43);

SQL:

select * from one join two on (one.twoid = two.twoid);

และคอลัมน์ที่คุณได้รับกลับมามีoneid=1, data=42, และtwoid=2other=43

ตอนนี้จะเกิดอะไรขึ้นถ้าฉันเพิ่มคอลัมน์ลงในตารางที่หนึ่ง http://sqlfiddle.com/#!2/cd0b0/1

alter table one add column other text;

update one set other = 'foo';

และผลของฉันจากแบบสอบถามเช่นเดียวกับก่อนมีoneid=1, data=42, และtwoid=2other=foo

การเปลี่ยนแปลงในตารางใดตารางหนึ่งจะกระทบกับค่าของ a select *และในทันทีที่การเชื่อมโยงของคุณกับ 'อื่น ๆ ' กับ int กำลังจะเกิดข้อผิดพลาดและคุณไม่รู้ว่าทำไม

ถ้าแทนคำสั่ง SQL ของคุณคือ

select 
    one.oneid, one.data, two.twoid, two.other
from one join two on (one.twoid = two.twoid);

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


การจัดทำดัชนี

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

ดัชนี (สัมพันธ์กับ SO: วิธีการใช้ดัชนีในคำสั่ง select? )

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

หากคุณเป็นเพียงการเลือกพูดนามสกุลของผู้ใช้ (ซึ่งคุณทำมากและเพื่อให้มีดัชนีในนั้น), ฐานข้อมูลสามารถทำดัชนีเพียงสแกน ( ดัชนี postgres วิกิพีเดียเท่านั้นสแกน , MySQL ตารางการสแกน VS เต็ม การสแกนดัชนี , การสแกนดัชนีเท่านั้น: หลีกเลี่ยงการเข้าถึงตาราง )

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

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

การอ่านที่เกี่ยวข้อง


2
@Tonny ฉันเห็นด้วย - แต่เมื่อฉันตอบ (ก่อน) ฉันไม่เคยคิดว่าคำถามนี้จะสร้างการอภิปรายและความเห็นค่อนข้างมาก! มันชัดเจนที่จะสืบค้นเฉพาะคอลัมน์ที่มีชื่อเท่านั้นใช่มั้ย!
gbjbaanb

3
การทำลายทุกอย่างด้วยการเพิ่มคอลัมน์เป็นเหตุผลที่ดีที่รหัสควรเข้าถึงคอลัมน์ในชุดข้อมูลโดยใช้ชื่อไม่ใช่โดยลำดับที่เข้ารหัสยาก ...
Julia Hayward

1
@gbjbaanb มันสำหรับฉัน แต่ผู้คนจำนวนมากมาเขียนแบบสอบถาม SQL โดยไม่ต้องมีพื้นฐาน / ฝึกอบรมอย่างเป็นทางการ สำหรับพวกเขาอาจไม่ชัดเจน
Tonny

1
@ ไม่ถูกต้องฉันได้อัปเดตพร้อมบิตเพิ่มเติมเกี่ยวกับปัญหาการจัดทำดัชนี มีประเด็นอื่นใดอีกที่ฉันควรนำมาซึ่งความผิดของselect *?

3
ว้าวคำตอบที่ได้รับการยอมรับนั้นแย่มากที่อธิบายสิ่งที่ฉันลงคะแนนได้จริง ประหลาดใจที่นี่ไม่ใช่คำตอบที่ยอมรับ +1
Ben Lee

38

ข้อกังวลอื่น: ถ้าเป็นJOINคิวรีและคุณกำลังดึงผลลัพธ์คิวรีมาไว้ในอาเรย์แบบเชื่อมโยง (เช่นใน PHP) มันอาจจะเป็นบั๊กได้

สิ่งที่เป็นที่

  1. ถ้าตารางfooมีคอลัมน์idและname
  2. ถ้าตารางbarมีคอลัมน์idและaddress,
  3. และในรหัสของคุณที่คุณใช้ SELECT * FROM foo JOIN bar ON foo.id = bar.id

เดาว่าจะเกิดอะไรขึ้นเมื่อมีคนเพิ่มคอลัมน์nameลงในbarตาราง

รหัสจะหยุดทำงานอย่างถูกต้องทันทีเพราะตอนนี้nameคอลัมน์ปรากฏในผลลัพธ์สองครั้งและหากคุณเก็บผลลัพธ์ไว้ในอาร์เรย์ข้อมูลจากวินาทีname( bar.name) จะเขียนทับแรกname( foo.name)!

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

(เรื่องจริง).

ดังนั้นอย่าใช้*ให้ควบคุมคอลัมน์ที่คุณดึงข้อมูลและใช้นามแฝงตามความเหมาะสม


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

4
ในทางทฤษฎี แต่ถ้าคุณใช้ไวด์การ์ดเพื่อความสะดวกคุณต้องใช้มันเพื่อให้คอลัมน์ทั้งหมดมีอยู่โดยอัตโนมัติและไม่ต้องคอยอัปเดตคิวรีเมื่อตารางโตขึ้น หากคุณกำลังระบุคอลัมน์ทุกคอลัมน์คุณจะถูกบังคับให้ไปที่คิวรีเพื่อเพิ่มอีกหนึ่งคอลัมน์ในSELECTประโยคของคุณและนี่คือเมื่อคุณหวังว่าจะเห็นชื่อนั้นไม่ซ้ำกัน BTW ฉันไม่คิดว่ามันหายากมากในระบบที่มีฐานข้อมูลขนาดใหญ่ ดังที่ฉันพูดฉันเคยใช้เวลาสองสามชั่วโมงในการตามล่าหาข้อผิดพลาดนี้ในรหัส PHP ขนาดใหญ่ และฉันพบอีกกรณีหนึ่งตอนนี้: stackoverflow.com/q/17715049/168719
Konrad Morawski

3
ฉันใช้เวลาหนึ่งชั่วโมงเมื่อสัปดาห์ที่แล้วเพื่อให้ได้สิ่งนี้ผ่านหัวหน้าที่ปรึกษา เขาควรจะเป็นกูรู SQL ... ถอนหายใจ ...
Tonny

22

การค้นหาทุกคอลัมน์อาจถูกต้องตามกฎหมายอย่างสมบูรณ์ในหลายกรณี

การสอบถามทุกคอลัมน์เสมอไม่ใช่

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

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

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

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

BTW ฉันได้พูดว่า "คน [คนอื่น]" สองสามครั้งข้างต้น จำไว้ว่าฐานข้อมูลนั้นมีผู้ใช้หลายคนอย่างแท้จริง คุณอาจไม่สามารถควบคุมสิ่งที่คุณคิดว่าคุณทำ


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

1
@supercat นั่นเป็นเพียงแค่เรื่องการใช้งานที่ถูกต้องเท่านั้นสำหรับ "SELECT *" ที่ฉันนึกได้ และยิ่งไปกว่านั้นฉันต้องการ จำกัด การสืบค้นไว้ที่ "SELECT TOP 10 *" (ใน MS SQL) หรือเพิ่ม "LIMIT 10" (mySQL) หรือเพิ่ม "WHERE ROWNUM <= 10" (Oracle) โดยทั่วไปแล้วในกรณีนี้มันจะเกี่ยวกับ "คอลัมน์อะไรบ้างและมีข้อมูลตัวอย่าง" มากกว่าเนื้อหาที่สมบูรณ์
Tonny

@Tonny: SQL Server เปลี่ยนสคริปต์เริ่มต้นเพื่อเพิ่มTOPข้อ จำกัด ฉันไม่แน่ใจว่ามีความสำคัญเพียงใดหากรหัสอ่านได้มากเท่าที่สนใจจะแสดงและจากนั้นจะยกเลิกการสืบค้น ฉันคิดว่าการตอบคำถามมีการประมวลผลค่อนข้างขี้เกียจ แต่ฉันไม่ทราบรายละเอียด ในกรณีใด ๆ ผมคิดว่าแทนที่จะบอกว่ามัน "ไม่ได้ถูกต้องตามกฎหมาย" มันจะดีกว่าที่จะบอกว่า "... ถูกต้องตามกฎหมายในไกลน้อย"; โดยพื้นฐานแล้วฉันจะสรุปคดีที่ถูกกฎหมายว่าเป็นกรณีที่ผู้ใช้จะมีความคิดที่ดีกว่าสิ่งที่มีความหมายมากกว่าโปรแกรมเมอร์
supercat

@supercat ฉันสามารถเห็นด้วยกับที่ และฉันชอบวิธีที่คุณวางไว้ในประโยคสุดท้ายของคุณ ฉันต้องจำไว้
Tonny

11

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

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

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

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


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

@Craig: SQL เป็นเรื่องธรรมดาในฐานข้อมูลเชิงสัมพันธ์อย่างกว้างขวาง นั่นไกลจาก DB ประเภทเดียว แต่ ... และมีเหตุผลที่ฐานข้อมูลที่ทันสมัยกว่ามักเรียกว่า NoSQL : ไม่มีใครรู้ว่าฉันจะไปเรียก SQL "ฉลาด" โดยไม่ต้องเหน็บแนม มันเป็นตัวเลือกที่น้อยกว่าตัวเลือกมากมายเท่าที่ฐานข้อมูลเชิงสัมพันธ์เกี่ยวข้อง
cHao

@cHao ฉันรู้มากเกี่ยวกับฐานข้อมูลประเภทอื่น ๆมาหลายทศวรรษแล้ว ฐานข้อมูล "nosql" เลือกมาโดยตลอด "NoSQL" ไม่ได้เป็นแนวคิดใหม่จากระยะไกล ออมของยังได้รับรอบตลอดไปและพวกเขาได้ช้าเสมอ ช้า! = ดี สำหรับความสง่างาม (LINQ?) คุณไม่สามารถโน้มน้าวฉันได้ว่าสิ่งนี้มีเหตุผลหรือสง่างามสำหรับประโยคที่: Customer customer = this._db.Customers.Where( “it.ID = @ID”, new ObjectParameter( “ID”, id ) ).First();ดูเวลาที่จะทำผิดในหน้า 2
เครก

@Craig: อย่าให้ฉันเริ่มต้นด้วย ORM เกือบทุกระบบออกมีความน่ากลัวและสิ่งที่เป็นนามธรรมรั่วไหลทั่วทุกสถานที่ นั่นเป็นเพราะบันทึกฐานข้อมูลเชิงสัมพันธ์ไม่ใช่วัตถุ - ดีที่สุดเพราะเป็นส่วนหนึ่งของวัตถุ แต่สำหรับ LINQ คุณต้องการไปที่นั่นจริงๆเหรอ? การเทียบเท่า SQLish เป็นสิ่งที่คล้ายvar cmd = db.CreateCommand(); cmd.CommandText = "SELECT TOP 1 * FROM Customers WHERE ID = @ID"; cmd.Parameters.AddWithValue("@ID", id); var result = cmd.ExecuteReader();.... แล้วดำเนินการสร้างลูกค้าจากแต่ละแถว LINQ ชนะกางเกงอย่างนั้น
cHao

@ Craig: ได้รับมันไม่ได้สง่างามเท่าที่ควร แต่มันจะไม่สวยงามเท่าที่ฉันต้องการจนกว่าจะสามารถแปลง. net code เป็น SQL :) ณ จุดนี้คุณสามารถพูดvar customer = _db.Customers.Where(it => it.id == id).First();ได้
cHao

8

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

นอกจากนี้ในแนวทางแบบ N-tiered วิธีที่ดีที่สุดในการแยกสคีมาฐานข้อมูลให้หยุดชะงักไปที่ระดับข้อมูล หากระดับข้อมูลของคุณส่งผ่าน * ไปยังตรรกะทางธุรกิจและเป็นไปได้มากที่สุดในระดับการนำเสนอคุณกำลังขยายขอบเขตการดีบักของคุณแบบทวีคูณ


3
นี่อาจเป็นหนึ่งในเหตุผลที่สำคัญที่สุดที่นี่และมันเป็นเพียงส่วนเล็กน้อยของคะแนนเสียง การบำรุงรักษาของ codebase ที่ทิ้งกระจุยกระจายกับselect *แย่มาก!
Eamon Nerbonne

6

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

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


1

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


3
เห็นด้วยแม้ว่าฉันจะแนะนำให้ดึงค่าจากชุดผลลัพธ์ตามชื่อคอลัมน์ในทุกกรณี
Rory Hunter

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

1

ฉันไม่เห็นเหตุผลใด ๆ ที่คุณไม่ควรใช้เพื่อจุดประสงค์ในการสร้าง - ดึงคอลัมน์ทั้งหมดจากฐานข้อมูล ฉันเห็นสามกรณี:

  1. คอลัมน์จะถูกเพิ่มในฐานข้อมูลและคุณต้องการในรหัสด้วย a) With * จะล้มเหลวด้วยข้อความที่เหมาะสม b) หากไม่มี * จะใช้งานได้ แต่จะไม่ทำในสิ่งที่คุณคาดหวังซึ่งไม่ดีนัก

  2. มีการเพิ่มคอลัมน์ในฐานข้อมูลและคุณไม่ต้องการให้เป็นรหัส a) ด้วย * จะล้มเหลว ซึ่งหมายความว่า * ไม่สามารถใช้งานได้อีกต่อไปเนื่องจากความหมายหมายถึง "เรียกข้อมูลทั้งหมด" b) หากไม่มี * จะใช้งานได้

  3. คอลัมน์จะถูกลบรหัสจะล้มเหลวอย่างใดอย่างหนึ่ง

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

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


หลักฐานของคุณไม่ถูกต้อง Select *มีวัตถุประสงค์เพื่อความสะดวกในการสอบถามแบบเฉพาะกิจไม่ใช่เพื่อการพัฒนาแอปพลิเคชัน หรือเพื่อใช้ในการสร้างเชิงสถิติแบบselect count(*)ที่ให้เอ็นจิ้นการสืบค้นตัดสินใจว่าจะใช้ดัชนีซึ่งจะใช้ดัชนีใดเป็นต้นและคุณจะไม่ส่งคืนข้อมูลคอลัมน์ใด ๆ หรือเพื่อใช้ใน clauses like where exists( select * from other_table where ... )ซึ่งอีกครั้งคือคำเชิญไปยังเอ็นจินการสืบค้นเพื่อเลือกพา ธ ที่มีประสิทธิภาพสูงสุดด้วยตนเองและเคียวรีย่อยจะถูกใช้เพื่อ จำกัด ผลลัพธ์จากเคียวรีหลักเท่านั้น ฯลฯ
Craig

@ Craig ฉันเชื่อว่าหนังสือทุกเล่ม / การสอนเกี่ยวกับ SQL บอกว่าselect *มีความหมายของการดึงคอลัมน์ทั้งหมด; หากแอปพลิเคชันของคุณต้องการสิ่งนี้จริงๆฉันไม่เห็นเหตุผลใด ๆ ว่าทำไมจึงไม่ใช้ คุณสามารถชี้ไปที่การอ้างอิงบางส่วน (Oracle, IBM, Microsoft ฯลฯ ) ที่กล่าวถึงวัตถุประสงค์ที่select *การสร้างไม่ได้เรียกคืนคอลัมน์ทั้งหมดได้หรือไม่?
m3th0dman

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

อาจมีกรณีขอบที่นี่หรือมีการปรับการใช้งานselect *ในแอปพลิเคชันการผลิตจริง แต่ลักษณะของกรณีขอบคือมันไม่ใช่กรณีทั่วไป :-)
Craig

@Craig เหตุผลที่มีต่อการเรียกคอลัมน์ทั้งหมดจากฐานข้อมูลไม่ได้กับการใช้select *; สิ่งที่ผมบอกว่าถ้าคุณต้องการคอลัมน์ทั้งหมดจริงๆผมไม่เห็นเหตุผลว่าทำไมคุณไม่ควรใช้select *; แม้ว่าจะมีบางสถานการณ์ที่จำเป็นต้องมีทุกคอลัมน์
m3th0dman

1

ลองใช้วิธีนี้ ... หากคุณค้นหาคอลัมน์ทั้งหมดจากตารางที่มีเพียงสตริงเล็ก ๆ หรือฟิลด์ตัวเลขจำนวนหนึ่งข้อมูลรวม 100k นั้น การปฏิบัติที่ไม่ดี แต่มันจะทำงาน ตอนนี้เพิ่มเขตข้อมูลเดียวที่เก็บพูดรูปภาพหรือเอกสารคำ 10mb ตอนนี้คิวรีที่ทำงานเร็วของคุณทันทีและเริ่มทำงานได้ไม่ดีเพียงเพราะมีการเพิ่มฟิลด์ลงในตาราง ... คุณอาจไม่จำเป็นต้องมีองค์ประกอบข้อมูลขนาดใหญ่ แต่เพราะคุณได้ทำSelect * from Tableไปแล้ว


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