ข้อความค้นหาของคุณเหมาะสมที่สุด ไวยากรณ์จะไม่สั้นลงมากแบบสอบถามจะไม่เร็วขึ้น:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
หากคุณต้องการทำให้ไวยากรณ์สั้นลงจริงๆให้ใช้นิพจน์ทั่วไปที่มีสาขา :
...
WHERE name ~ '^(B|D).*'
หรือเร็วกว่าเล็กน้อยด้วยคลาสตัวละคร :
...
WHERE name ~ '^[BD].*'
การทดสอบอย่างรวดเร็วโดยไม่ใช้ดัชนีให้ผลลัพธ์เร็วกว่าSIMILAR TO
สำหรับฉัน
ด้วยดัชนี B-Tree ที่เหมาะสมในสถานที่LIKE
ชนะการแข่งขันนี้โดยคำสั่งของขนาด
อ่านพื้นฐานเกี่ยวกับการจับคู่รูปแบบในคู่มือ
ดัชนีเพื่อประสิทธิภาพที่เหนือกว่า
หากคุณกังวลเกี่ยวกับประสิทธิภาพการทำงานให้สร้างดัชนีเช่นนี้สำหรับตารางที่ใหญ่กว่า:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
ทำให้ข้อความค้นหาประเภทนี้เร็วขึ้นตามลำดับความสำคัญ ข้อพิจารณาพิเศษใช้สำหรับลำดับการจัดเรียงเฉพาะโลแคล อ่านเพิ่มเติมเกี่ยวกับชั้นเรียนผู้ประกอบการในคู่มือ หากคุณกำลังใช้ภาษา "C" มาตรฐาน (คนส่วนใหญ่ไม่ได้) ดัชนีธรรมดา (ที่มีระดับผู้ประกอบการเริ่มต้น) จะทำ
ดัชนีดังกล่าวดีสำหรับรูปแบบการยึดซ้าย (การจับคู่จากจุดเริ่มต้นของสตริง)
SIMILAR TO
หรือนิพจน์ทั่วไปที่มีนิพจน์ยึดหลักซ้ายสามารถใช้ดัชนีนี้ได้เช่นกัน แต่ไม่ใช่กับสาขา(B|D)
หรือคลาสอักขระ[BD]
(อย่างน้อยในการทดสอบของฉันกับ PostgreSQL 9.0)
การจับคู่ Trigram หรือการค้นหาข้อความใช้ดัชนี GIN หรือ GiST พิเศษ
ภาพรวมของโอเปอเรเตอร์การจับคู่รูปแบบ
LIKE
( ~~
) นั้นง่ายและรวดเร็ว แต่มีข้อ จำกัด ในขีดความสามารถ
ILIKE
( ~~*
) ตัวแปรตัวพิมพ์เล็กและใหญ่
pg_trgm ขยายการสนับสนุนดัชนีสำหรับทั้งสอง
~
(การจับคู่นิพจน์ทั่วไป) มีประสิทธิภาพ แต่ซับซ้อนกว่าและอาจช้ากว่าอะไรก็ได้สำหรับนิพจน์พื้นฐาน
SIMILAR TO
เป็นเพียงไม่มีจุดหมาย การแบ่งครึ่งที่แปลกประหลาดLIKE
และการแสดงออกปกติ ฉันไม่เคยใช้มัน ดูด้านล่าง
%คือ "ความคล้ายคลึงกัน" pg_trgm
ผู้ประกอบการที่ให้บริการโดยโมดูลเพิ่มเติม ดูด้านล่าง
@@
เป็นผู้ดำเนินการค้นหาข้อความ ดูด้านล่าง
pg_trgm - การจับคู่ trigram
เริ่มต้นด้วยการPostgreSQL 9.1คุณสามารถอำนวยความสะดวกในการขยายpg_trgm
การให้การสนับสนุนดัชนีใด ๆ LIKE
/ ILIKE
รูปแบบ (และรูปแบบที่เรียบง่ายด้วย regexp ~
) โดยใช้ GIN หรือ GIST ดัชนี
รายละเอียดตัวอย่างและลิงค์:
pg_trgm
ยังมีตัวดำเนินการเหล่านี้ :
%
- ตัวดำเนินการ "ความคล้ายคลึงกัน"
<%
(commutator %>
:) - ตัวดำเนินการ "word_similarity" ใน Postgres 9.6 หรือใหม่กว่า
<<%
(commutator %>>
:) - โอเปอเรเตอร์ "เข้มงวด_word_similarity" ใน Postgres 11 หรือใหม่กว่า
ค้นหาข้อความ
เป็นการจับคู่รูปแบบพิเศษที่มีโครงสร้างพื้นฐานแยกต่างหากและประเภทดัชนี มันใช้พจนานุกรมและการกั้นและเป็นเครื่องมือที่ยอดเยี่ยมในการค้นหาคำในเอกสารโดยเฉพาะอย่างยิ่งสำหรับภาษาธรรมชาติ
รองรับการจับคู่คำนำหน้าด้วย:
เช่นเดียวกับการค้นหาวลีตั้งแต่ Postgres 9.6:
พิจารณาการแนะนำในคู่มือและภาพรวมของผู้ประกอบการและฟังก์ชั่น
เครื่องมือเพิ่มเติมสำหรับการจับคู่สตริงฟัซซี่
โมดูลfuzzystrmatchเพิ่มเติมมีตัวเลือกเพิ่มเติมบางอย่าง แต่ประสิทธิภาพโดยทั่วไปจะด้อยกว่าทุกข้อ
โดยเฉพาะอย่างยิ่งการใช้งานที่หลากหลายของlevenshtein()
ฟังก์ชั่นอาจเป็นเครื่องมือ
ทำไมจึงมีการแสดงออกปกติ ( ~
) เสมอเร็วกว่าSIMILAR TO
?
คำตอบนั้นง่าย SIMILAR TO
นิพจน์จะถูกเขียนใหม่เป็นนิพจน์ปกติภายใน ดังนั้นสำหรับทุกSIMILAR TO
นิพจน์จะมีนิพจน์ทั่วไปที่เร็วกว่าอย่างน้อยหนึ่งนิพจน์ (ซึ่งจะช่วยประหยัดค่าใช้จ่ายในการเขียนนิพจน์) ไม่มีกำไรจากผลการดำเนินงานในการใช้เป็นที่เคยSIMILAR TO
และสำนวนที่เรียบง่ายที่สามารถทำได้ด้วยLIKE
( ~~
) จะเร็วขึ้นด้วยLIKE
ล่ะค่ะ
SIMILAR TO
ได้รับการสนับสนุนเฉพาะใน PostgreSQL เพราะสิ้นสุดในร่างแรกของมาตรฐาน SQL พวกเขายังไม่ได้กำจัดมัน แต่มีแผนการที่จะลบมันและรวมการแข่งขัน regexp แทน - หรือดังนั้นฉันได้ยิน
EXPLAIN ANALYZE
เปิดเผยมัน ลองกับโต๊ะตัวเองสิ!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
เผย:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
ถูกเขียนใหม่ด้วยนิพจน์ทั่วไป ( ~
)
ประสิทธิภาพสูงสุดสำหรับกรณีนี้โดยเฉพาะ
แต่EXPLAIN ANALYZE
เผยให้เห็นมากขึ้น ลองด้วยดัชนีที่กล่าวถึงข้างต้น:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
เผย:
...
-> Bitmap Heap Scan on spelers (cost= ...
Filter: (name ~ '^B.*'::text)
-> Bitmap Index Scan on spelers_name_text_pattern_ops_idx (cost= ...
Index Cond: ((prod ~>=~ 'B'::text) AND (prod ~<~ 'C'::text))
ภายในมีดัชนีที่ไม่รู้จักสถานที่ ( text_pattern_ops
หรือใช้สถานที่C
) การแสดงออกทางซ้ายจอดทอดสมออยู่ที่เรียบง่ายมีการเขียนใหม่กับผู้ประกอบการเหล่านี้รูปแบบข้อความ: ~>=~
, ~<=~
, ,~>~
~<~
เป็นกรณีนี้สำหรับ~
, ~~
หรือSIMILAR TO
เหมือนกัน
เช่นเดียวกับที่เป็นจริงสำหรับดัชนีในvarchar
ประเภทvarchar_pattern_ops
หรือกับchar
bpchar_pattern_ops
ดังนั้นนำไปใช้กับคำถามเดิมนี่คือวิธีที่เร็วที่สุดที่เป็นไปได้ :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
แน่นอนหากคุณควรค้นหาชื่อย่อที่อยู่ติดกันคุณสามารถทำให้ง่ายขึ้นได้อีก:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
การได้รับมากกว่าการใช้แบบธรรมดา~
หรือ~~
เล็ก หากผลการดำเนินงานไม่ใช่ข้อกำหนดที่สำคัญที่สุดของคุณคุณก็ควรยึดติดกับผู้ดำเนินการมาตรฐาน - มาถึงสิ่งที่คุณมีอยู่แล้วในคำถาม
s.name
จัดทำดัชนีหรือไม่