เป็นไปได้ INDEX บนเขตข้อมูล VARCHAR ใน MySql


40

ฉันทำงานในฐานข้อมูล MySqlโดยมีตารางดังนี้:

+--------------+
|  table_name  |
+--------------+
|    myField   |
+--------------+

... และฉันต้องการสอบถามจำนวนมากเช่นนี้(มี 5-10 สตริงในรายการ) :

SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)

จะมีแถวที่ไม่ซ้ำประมาณ 24.000.000 แถว

1)ฉันควรใช้ a FULLTEXTหรือและที่INDEXสำคัญสำหรับของฉันVARCHAR(150)?
2)ถ้าฉันเพิ่มตัวอักษรจาก 150 เป็น 220 หรือ 250 ... มันจะสร้างความแตกต่างได้หรือไม่? (มีวิธีการคำนวณหรือไม่?)
3)ตามที่ฉันพูดพวกเขาจะไม่ซ้ำกันดังนั้นสนามของฉันควรเป็นคีย์หลัก การเพิ่มคีย์หลักในฟิลด์ซึ่งเป็น VARCHAR INDEX / FULLTEXT นั้นหาได้ยากหรือไม่


คุณไม่จำเป็นต้องใช้หลักเพื่อความเป็นเอกลักษณ์ มีอยู่แล้วที่ไม่ซ้ำกันสำหรับการที่
kommradHomer

คำตอบ:


62

คำแนะนำ # 1: การจัดทำดัชนีมาตรฐาน

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    key (myfield)
);

หากคุณจัดทำดัชนีเช่นนี้คุณสามารถค้นหาสตริงทั้งหมดหรือทำการค้นหา LIKE ที่มุ่งเน้นด้านซ้าย

SUGGESTION # 2: การจัดทำดัชนี FULLTEXT

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    fulltext (myfield)
);

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

นี่คือโพสต์อื่น ๆ ของฉันจากสองปีที่ผ่านมาในดัชนี FULLTEXT

คำแนะนำ # 3: การทำดัชนีแฮช

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    hashmyfield char(32) not null,
    primary key (id),
    key (hashmyfield)
);

หากคุณกำลังมองหาค่าหนึ่งค่าและค่าเหล่านั้นอาจมีความยาวเกิน 32 อักขระคุณสามารถเก็บค่าแฮชได้:

INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));

ด้วยวิธีนี้คุณเพียงแค่ค้นหาค่าแฮชเพื่อดึงผลลัพธ์

SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');

ให้มันลอง !!!


ฉันไม่มีชื่อเสียงพอที่จะโหวตคำตอบของคุณ แต่ฉันต้องบอกว่ามันยอดเยี่ยมมาก ขอบคุณสำหรับคำอธิบายและตัวอย่าง ฉันคิดว่าการจัดทำดัชนีแฮชดีที่สุดสำหรับกรณีของฉันมันเป็นทางออกที่ยอดเยี่ยม แต่ก็ยังมีคำถามหนึ่งข้อ: คุณคิดว่าขีด จำกัด ของแถวสำหรับการค้นหาที่รวดเร็วในตารางจะเป็นอย่างไร [ใช้เป็น KEY the VARCHAR (32) สำหรับการค้นหา]
Mark Tower

2
ตัวเลือกแฮชที่นี่ยังคงเป็นข้อความและ 32 ไบต์สำหรับ 16 ไบต์ คุณสามารถใช้ฟิลด์ bigint ที่มี Conv (ซ้าย (md5 ('what'), 16), 16, -10) ไม่มีตัวเลข 16 ไบต์ แต่คุณอาจพบว่าครึ่งหนึ่งของ md5 เพียงพอและจากนั้นเป็นเพียง 8 ไบต์ในดัชนี
atxdba

1
ไม่ดีที่จะใช้ MD5 หรือ SHA1 เพื่อสร้างสตริงที่จะถูกทำดัชนี การกระจายของสตริงที่ผลิตโดยฟังก์ชั่นการแฮ็กเช่น MD5 หรือ SHA1 นั้นจะถูกสุ่มในพื้นที่ขนาดใหญ่ซึ่งลดประสิทธิภาพของดัชนีของคุณซึ่งสามารถทำให้คำสั่ง INSERT และ SELECT ช้าลง นี่คือคำอธิบายที่โพสต์: code-epicenter.com/…
Mr.M

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

สิ่งนี้คล้ายกับการค้นหาซ้ายlike 'a%'หรือไม่
นักบัญชี

18

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

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

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

หากเราสร้างดัชนีเฉพาะอักขระตัวแรก (N = 1) ตารางดัชนีจะมีลักษณะดังนี้ตารางต่อไปนี้:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

ในกรณีนี้การเลือกดัชนีเท่ากับ IS = 1/3 = 0.33

ให้เราดูว่าจะเกิดอะไรขึ้นถ้าเราเพิ่มจำนวนอักขระที่จัดทำดัชนีเป็นสอง (N = 2)

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

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

มีสองวิธีที่คุณสามารถทำการคำนวณสำหรับตารางฐานข้อมูลของคุณ ฉันจะทำการสาธิตเกี่ยวกับการถ่ายโอนข้อมูลฐานข้อมูลนี้

สมมติว่าเราต้องการเพิ่มคอลัมน์last_nameในพนักงานตารางลงในดัชนีและเราต้องการกำหนดจำนวนNที่น้อยที่สุดซึ่งจะสร้างการเลือกดัชนีที่ดีที่สุด

ก่อนอื่นให้เราระบุนามสกุลที่พบบ่อยที่สุด:

select count(*) as cnt, last_name from employees group by employees.last_name order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

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

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

มีคำนำหน้าทั้งหมดเกิดขึ้นอีกมากมายซึ่งหมายความว่าเราต้องเพิ่มหมายเลข N จนกว่าค่าจะใกล้เคียงกับตัวอย่างก่อนหน้านี้

นี่คือผลลัพธ์สำหรับ N = 9

select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

นี่คือผลลัพธ์สำหรับ N = 10

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

นี่เป็นผลลัพธ์ที่ดีมาก ซึ่งหมายความว่าเราสามารถสร้างดัชนีในคอลัมน์last_nameโดยสร้างดัชนีเฉพาะอักขระ 10 ตัวแรกเท่านั้น ในคอลัมน์นิยามตารางlast_nameถูกกำหนดเป็นVARCHAR(16)และหมายความว่าเราได้บันทึก 6 ไบต์ (หรือมากกว่านั้นถ้ามีอักขระ UTF8 ในนามสกุล) ต่อรายการ ในตารางนี้มีค่าที่แตกต่างกัน 1637 คูณด้วย 6 ไบต์คือประมาณ 9KB และจินตนาการว่าตัวเลขนี้จะเติบโตอย่างไรถ้าตารางของเรามีล้านแถว

คุณสามารถอ่านวิธีการอื่น ๆ ในการคำนวณจำนวนNในการโพสต์ของฉันดัชนีคำนำหน้าใน MySQL

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


นี่เป็นคำตอบที่ละเอียดมากสำหรับคำถามอื่น
mustaccio

1
คุณล้อเล่นกับฉันไหม
Mr.M

คุณสามารถอธิบายสิ่งที่ผิดหรือสิ่งที่ไม่สามารถนำไปใช้กับคำถามได้หรือไม่
Mr.M

2
เฮ้ MrD ฉันชอบคำตอบของคุณ ทำไม ในคำตอบเก่าของฉันที่ผมกล่าวในข้อเสนอแนะ # If you index like this, you can either look for the whole string or do left-oriented LIKE searches1: ฉันยังกล่าวในข้อเสนอแนะ # If you are looking for one specific value and those values could be lengths well beyond 32 characters, you could store the hash value:3: คำตอบของคุณแสดงให้เห็นอย่างเพียงพอว่าทำไมไม่ควรใช้ปุ่มขนาดใหญ่และควรจัดทำดัชนีตัวอักษรซ้ายสุดซึ่งอาจทำให้ประสิทธิภาพแตกต่างกัน คำตอบของคุณอยู่ที่นี่ +1 สำหรับคำตอบของคุณและยินดีต้อนรับสู่ DBA StackExchange
RolandoMySQLDBA
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.