เหตุใดการใช้คีย์สตริงจึงถือว่าเป็นความคิดที่ไม่ดี


24

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

ยกตัวอย่างง่ายๆสองอย่างถ้าช่วยได้:

ตารางคล้าย SQL ที่แถวถูกทำดัชนีโดยคีย์หลักของสตริง

. NET Dictionary ที่มีรหัสเป็น Strings


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

3
โดยปกติคุณต้องการคีย์หลักที่ไม่เปลี่ยนแปลงตลอดอายุการใช้งานของวัตถุ / แถว ตัวอย่างเช่นusernameในฐานะคีย์หลักของusersตารางอาจไม่ใช่ความคิดที่ดีที่สุดและคุณต้องการรหัสเพิ่มโดยอัตโนมัติ แต่นั่นusernameเป็นสตริงเป็นเพียงอุบัติเหตุการเป็นทรัพย์สินที่ไม่แน่นอนเป็นปัญหาหลัก
CodesInChaos

ในฐานข้อมูลพิจารณาว่าจะสร้างดัชนีสตริงอย่างไรเมื่อเทียบกับจำนวนเต็ม

@CodesInChaos ฉันหวังว่าฉันจะจำได้ว่าฉันพบคดีส่วนใหญ่ที่ไหน แต่ตอนนี้ฉันสามารถวางบิตที่ทำให้ฉันนึกถึงปัญหา มันมาจากสไลด์โชว์ GDC โดย Valve ซึ่งกล่าวถึงบทสนทนาของเกมและเก็บข้อเท็จจริงเกี่ยวกับโลกในคู่ <key = string, value = object>

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

คำตอบ:


17

ทุกอย่างเกี่ยวข้องกับสองสิ่งโดยทั่วไป:

1) ความเร็วในการค้นหา (ที่จำนวนเต็มเช่นค่าโดยสารดีกว่ามาก)

2) ขนาดของดัชนี (โดยที่ดัชนีสตริงจะกระจาย)

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

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


ไม่เสมอไป - มี GUID ที่เพิ่มขึ้นเป็นไปได้ ดัชนีจะยังคงมีขนาดใหญ่กว่า แต่การลงโทษการค้นหาจะไม่เลวร้ายนัก
Sam

7
ที่จริงแล้วพวกเขาก็สบายดี คุณต้องดูความสัมพันธ์ระหว่างเวลาของดิสก์เวลา IO และการเปรียบเทียบค่าในหน่วยความจำ ตั้งแต่การเข้าถึงดิสก์ครั้งการเปรียบเทียบหน่วยความจำล้นสิ่งเดียวที่สำคัญในการวิเคราะห์ประสิทธิภาพของฐานข้อมูลคือ IO ไม่ว่าคีย์จะเป็น GUID สตริงหรือเลขจำนวนเต็มไม่สำคัญอย่างแท้จริง ขนาดดัชนีมีผลต่อจำนวนค่าดัชนีที่พอดีในหน้าเดียว แต่ไม่ว่าคีย์จะเป็น 4 ไบต์ int (ซึ่งอาจไม่ใหญ่พอและไม่สามารถสร้างลูกค้าได้) หรือค่า 16 ไบต์ไม่ใช่ประเด็นที่มีความสำคัญ ในบางฐานข้อมูล rowId สามารถมีขนาด 16 ไบต์
ipaul

9

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

คุณสามารถพูดได้เล็กน้อยและชัดเจน แต่ยังมีตัวอย่างโค้ด. NET จำนวนมากรอบ ๆ เว็บที่ใช้ตัวอักษรสตริงและเผยแพร่การปฏิบัติที่น่าสงสัยนี้ ASP.NET ที่มีเซสชันทั้งหมด ViewStates และ QueryParams เกลื่อนไปทั่ว codebase มีความผิดโดยเฉพาะที่นี่


ไม่น่ารำคาญ IMHO ฉันเคยเห็นกรณีที่มีกุญแจ"1"และ"1 "อยู่ในตารางเดียวกัน
pswg

รับความสนุกสนานมากยิ่งขึ้นเมื่อคุณเพิ่มความไวของตัวพิมพ์ในการผสมด้วย การมองเห็นคนจำนวนมากรวมทั้งตัวฉันสะดุดเข้ากับสิ่งนั้นโดยตรง
Tony Hopkinson

ดียิ่งกว่าการใช้ค่าคงที่ใน C # อย่างน้อยก็ใช้นิพจน์แทน ด้วยวิธีนี้คุณสามารถสร้างสตริงของคุณจากชื่อเมธอด / คุณสมบัติอื่น ๆ ดังนั้นการค้นหาสตริงของคุณจะปลอดภัยและเป็นมิตร
GoatInTheMachine

4

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

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

มีสองเหตุผลที่ฉันมักจะเพิ่มกุญแจตัวแทน:

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

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

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

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

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


ไม่ใช่ศูนย์ถ้าคุณจัดการเพื่อให้ชนิดจำนวนเต็มล้อมรอบกลับเป็นศูนย์ สำหรับประเภท 32 บิตที่ไม่ได้ลงชื่อนั่นเป็นเพียง 4G ออกไปซึ่งรบกวนอยู่ใกล้กับ "บันทึกนับพันล้านรายการ" ...
Donal Fellows

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

1

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


1

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

หากจำนวนเต็มทำให้ช่วงงานฉลาดและการประมวลผลราคาแพงจำนวนมากไม่จำเป็นต้องรู้ว่าจำนวนเต็มหมายถึงอะไรให้ใช้อันใดอันหนึ่ง


0

คุณได้รับข้อมูลผิดจาก Hashtable อย่างใด

คุณหมายถึง "DaytimeTelephone" หรือ "EveningTelephone" หรือไม่

หรือ

คุณหมายถึง 1234567 หรือ 1234576

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


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

-1

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


2
คำตอบนี้ไม่ได้เพิ่มอะไรเลยที่ยังไม่ได้พูดในคำตอบอื่นซึ่งพูดได้ดีกว่า
Martijn Pieters

-2

คีย์สตริงจะทำให้รู้สึกเมื่อมันมาถึงตารางการค้นหาที่มีประมาณสตริงสั้น ๆ 10-100; ข้อมูลที่เกี่ยวข้องนั้นสามารถอ่านได้ + เช่นการติดตามการเปลี่ยนแปลง (ตัวเลข / guid id เทียบกับสตริงเช่น "ผู้ดูแลระบบ"); btw ฐานข้อมูลสมาชิก ASP.NET ใช้คีย์สตริงสำหรับ AspNetRoles

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