ใช้โมดูล unaccentสำหรับสิ่งนั้นซึ่งแตกต่างอย่างสิ้นเชิงกับสิ่งที่คุณกำลังเชื่อมโยง
unaccent คือพจนานุกรมค้นหาข้อความที่ลบสำเนียง (เครื่องหมายกำกับเสียง) ออกจากตัวอักษร
ติดตั้งหนึ่งครั้งต่อฐานข้อมูลด้วย:
CREATE EXTENSION unaccent;
หากคุณได้รับข้อผิดพลาดเช่น:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
ติดตั้งแพ็คเกจ Contrib บนเซิร์ฟเวอร์ฐานข้อมูลของคุณตามที่ได้รับคำแนะนำในคำตอบที่เกี่ยวข้องนี้:
เหนือสิ่งอื่นใดมันมีฟังก์ชันที่unaccent()คุณสามารถใช้ได้กับตัวอย่างของคุณ (ซึ่งLIKEดูเหมือนว่าไม่จำเป็น)
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
ดัชนี
การใช้ดัชนีสำหรับชนิดของแบบสอบถามที่สร้างดัชนีในการแสดงออก อย่างไรก็ตาม Postgres ยอมรับIMMUTABLEฟังก์ชันสำหรับดัชนีเท่านั้น หากฟังก์ชันสามารถส่งคืนผลลัพธ์ที่แตกต่างกันสำหรับอินพุตเดียวกันดัชนีอาจแตกอย่างเงียบ ๆ
unaccent()STABLEไม่เท่านั้นIMMUTABLE
แต่น่าเสียดายที่unaccent()เป็นเพียงไม่STABLE IMMUTABLEตามหัวข้อนี้เกี่ยวกับ pgsql-bugsนี่เป็นเพราะสาเหตุสามประการ:
- ขึ้นอยู่กับลักษณะการทำงานของพจนานุกรม
- ไม่มีการเชื่อมต่อแบบใช้สายกับพจนานุกรมนี้
- ดังนั้นจึงขึ้นอยู่กับกระแส
search_pathซึ่งสามารถเปลี่ยนแปลงได้ง่าย
บทเรียนบางอย่างIMMUTABLEเกี่ยวกับการสั่งเว็บเพียงแค่เปลี่ยนความผันผวนของฟังก์ชั่น วิธีการบังคับแบบเดรัจฉานนี้สามารถทำลายได้ภายใต้เงื่อนไขบางประการ
คนอื่น ๆ แนะนำฟังก์ชั่นเสื้อคลุมแบบธรรมดาIMMUTABLE (เหมือนที่ฉันทำเองในอดีต)
มีการถกเถียงกันอย่างต่อเนื่องว่าจะสร้างตัวแปรด้วยพารามิเตอร์สองตัว IMMUTABLEที่ประกาศพจนานุกรมที่ใช้อย่างชัดเจนหรือไม่ อ่านที่นี่หรือที่นี่
อีกหนึ่งทางเลือกที่จะเป็นโมดูลนี้ด้วยการเปลี่ยนรูปunaccent()ฟังก์ชั่นโดย Musicbrainzให้บน Github ยังไม่ได้ทดสอบด้วยตัวเอง. ฉันคิดว่าฉันมีความคิดที่ดีกว่านี้ :
ดีที่สุดสำหรับตอนนี้
วิธีนี้เป็นวิธีที่มีประสิทธิภาพมากขึ้นเป็นโซลูชั่นอื่น ๆ ที่ลอยอยู่รอบ ๆ และปลอดภัยมากขึ้น
สร้างIMMUTABLEฟังก์ชัน SQL wrapper ที่เรียกใช้รูปแบบสองพารามิเตอร์ด้วยฟังก์ชันและพจนานุกรมที่มีคุณสมบัติสคีมาแบบใช้สายยาก
เนื่องจากการซ้อนฟังก์ชันที่ไม่เปลี่ยนรูปจะปิดการใช้งานฟังก์ชันอินไลน์อิงตามสำเนาของฟังก์ชัน C (ปลอม) ที่ประกาศIMMUTABLEด้วยเช่นกัน ใช้เพียงวัตถุประสงค์เพื่อนำมาใช้ในฟังก์ชั่นเสื้อคลุม SQL ไม่ได้มีไว้สำหรับใช้เอง
จำเป็นต้องมีความซับซ้อนเนื่องจากไม่มีวิธีการต่อสายพจนานุกรมในการประกาศฟังก์ชัน C (จำเป็นต้องแฮ็กโค้ด C เอง) ฟังก์ชัน SQL wrapper จะทำเช่นนั้นและอนุญาตให้ทั้งฟังก์ชันอินไลน์และดัชนีนิพจน์
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
ดร็อปPARALLEL SAFEจากทั้งสองฟังก์ชันสำหรับ Postgres 9.5 ขึ้นไป
publicเป็นสคีมาที่คุณติดตั้งส่วนขยาย ( publicเป็นค่าเริ่มต้น)
การประกาศประเภทอย่างชัดเจน ( regdictionary) ป้องกันการโจมตีสมมุติด้วยฟังก์ชันที่มีรูปแบบมากเกินไปโดยผู้ใช้ที่เป็นอันตราย
ก่อนหน้านี้ฉันสนับสนุนฟังก์ชัน wrapper ตามSTABLEฟังก์ชันที่unaccent()มาพร้อมกับโมดูล unaccent ที่ปิดการใช้งานอินไลน์ฟังก์ชั่น เวอร์ชันนี้ทำงานได้เร็วกว่าฟังก์ชัน Wrapper แบบธรรมดาถึง 10 เท่าที่ฉันมีก่อนหน้านี้
และนั่นเร็วกว่าเวอร์ชันแรกถึงสองเท่าซึ่งเพิ่มลงSET search_path = public, pg_tempในฟังก์ชันแล้ว - จนกระทั่งฉันค้นพบว่าพจนานุกรมนั้นสามารถเข้าเกณฑ์สคีมาได้เช่นกัน ยังคง (Postgres 12) ไม่ชัดเจนเกินไปจากเอกสาร
หากคุณไม่มีสิทธิ์ที่จำเป็นในการสร้างฟังก์ชัน C คุณจะกลับสู่การใช้งานที่ดีที่สุดอันดับสอง: IMMUTABLEฟังก์ชัน wrapper รอบ ๆSTABLE unaccent()ฟังก์ชันที่จัดเตรียมโดยโมดูล:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1)
$func$ LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;
ในที่สุดดัชนีนิพจน์เพื่อให้การสืบค้นรวดเร็ว :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
อย่าลืมสร้างดัชนีที่เกี่ยวข้องกับฟังก์ชันนี้ใหม่หลังจากการเปลี่ยนแปลงฟังก์ชันหรือพจนานุกรมเช่นการอัปเกรดรุ่นหลักแบบแทนที่ซึ่งจะไม่สร้างดัชนีขึ้นมาใหม่ รุ่นใหญ่ล่าสุดทั้งหมดมีการอัปเดตสำหรับunaccentโมดูล
ปรับการสืบค้นให้ตรงกับดัชนี (เพื่อให้ผู้วางแผนการสืบค้นใช้):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
คุณไม่ต้องการฟังก์ชันในนิพจน์ที่ถูกต้อง นอกจากนี้คุณยังสามารถจัดหาสตริงที่ไม่เน้นเสียง'Joao'ได้โดยตรง
ฟังก์ชั่นได้เร็วขึ้นไม่ได้แปลไปได้เร็วขึ้นมากแบบสอบถามโดยใช้ดัชนีการแสดงออก ซึ่งทำงานบนค่าที่คำนวณล่วงหน้าและรวดเร็วมากอยู่แล้ว แต่การบำรุงรักษาดัชนีและแบบสอบถามไม่ใช้ประโยชน์ของดัชนี
การรักษาความปลอดภัยสำหรับโปรแกรมไคลเอ็นต์ได้รับการรัดกุมด้วย Postgres 10.3 / 9.6.8 เป็นต้นคุณจำเป็นต้องกำหนดฟังก์ชันที่มีคุณสมบัติสคีมาและชื่อพจนานุกรมตามที่แสดงเมื่อใช้ในดัชนีใด ๆ ดู:
ลิเก
ในอักษรย่อPostgres 9.5 หรือเก่ากว่าเช่น 'Œ' หรือ 'ß' จะต้องขยายด้วยตนเอง (ถ้าคุณต้องการ) เนื่องจากunaccent()แทนที่ตัวอักษรตัวเดียวเสมอ:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
E A e a S
คุณจะหลงรักการอัปเดตนี้ถึงไม่มีใครสนใจใน Postgres 9.6 :
ขยายไฟล์contrib/unaccentมาตรฐานunaccent.rulesเพื่อจัดการตัวกำกับเสียงทั้งหมดที่ Unicode รู้จักและขยายตัวอักษรอย่างถูกต้อง (Thomas Munro, Léonard Benedetti)
ฉันเน้นตัวหนา ตอนนี้เราได้รับ:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
OE AE oe ae ss
การจับคู่รูปแบบ
สำหรับLIKEหรือILIKEกับรูปแบบที่กำหนดเองให้รวมเข้ากับโมดูลpg_trgmใน PostgreSQL 9.1 หรือใหม่กว่า สร้าง Trigram GIN (โดยทั่วไปแล้วจะดีกว่า) หรือดัชนีนิพจน์ GIST ตัวอย่างสำหรับ GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
สามารถใช้สำหรับการค้นหาเช่น:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
ดัชนี GIN และ GIST มีราคาแพงกว่าในการดูแลรักษามากกว่า btree ธรรมดา:
มีวิธีแก้ปัญหาที่ง่ายกว่าสำหรับรูปแบบที่ยึดด้านซ้ายเท่านั้น ข้อมูลเพิ่มเติมเกี่ยวกับการจับคู่รูปแบบและประสิทธิภาพ:
pg_trgmนอกจากนี้ยังมีประโยชน์ผู้ประกอบการสำหรับ "คล้ายคลึงกัน" ( %) และ "ระยะทาง" (<-> )
ดัชนี Trigram ยังรองรับนิพจน์ทั่วไปอย่างง่ายด้วย~et al และรูปแบบที่ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่จับคู่กับILIKE: