วิธีที่ดีกว่าสำหรับ“ LIKE หรือ LIKE หรือ LIKE หรือ LIKE หรือ LIKE”


10

ในคำถามนี้เขามีปัญหาเช่นเดียวกับฉัน ฉันต้องการบางสิ่งเช่น:

select * from blablabla 
where product 
like '%rock%' or
like '%paper%' or
like '%scisor%' or
like '%car%' or
like '%pasta%' 

นี่น่าเกลียดและไม่ได้ใช้ดัชนี .. ในกรณีนี้นี่เป็นวิธีเดียวที่จะทำเช่นนี้ (เพื่อเลือกหลายคำภายในสตริง) หรือฉันควรใช้ FULLTEXT?

ตามที่ฉันเข้าใจด้วยข้อความเต็มฉันสามารถเลือกหลายคำภายในสตริง

คำถามนี้พูดถึงเกี่ยวกับข้อความเต็มเช่นกัน


3
ชนิดข้อมูลของคอลัมน์ผลิตภัณฑ์คืออะไร โดยเฉลี่ยแล้วมีกี่ตัวอักษร?
โจ Obbish

คำตอบ:


17

โดยทั่วไปดัชนีข้อความแบบเต็มจะไม่ได้เป็น Bullet Magic และต้องการการบำรุงรักษาเพิ่มเติมพื้นที่ดิสก์และการเปลี่ยนแปลงรูปแบบการสืบค้นที่น่ารำคาญ

ถ้าคุณไม่ต้องการทำดัชนีเอกสารขนาดใหญ่อย่างแท้จริง (คิดว่าเนื้อความอีเมล, PDF, เอกสาร Word, ฯลฯ ) พวกเขากำลัง overkill (และถ้าเราซื่อสัตย์เราจะนำกระบวนการนั้นออกจาก SQL Server โดยสิ้นเชิงและ ใช้ Elasticsearch หรือสิ่งที่คล้ายกัน)

สำหรับกรณีใช้งานขนาดเล็กคอลัมน์ที่คำนวณโดยทั่วไปจะเป็นวิธีที่ดีกว่า

นี่คือการตั้งค่าการสาธิตอย่างรวดเร็ว:

use tempdb

CREATE TABLE #fulltextindexesarestupid (Id INT PRIMARY KEY CLUSTERED, StopAbusingFeatures VARCHAR(100))

INSERT #fulltextindexesarestupid (Id)
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY (@@ROWCOUNT))
FROM sys.messages AS m
CROSS JOIN sys.messages AS m2

UPDATE #fulltextindexesarestupid
SET StopAbusingFeatures = CASE WHEN Id % 15 = 0 THEN 'Bad'
                               WHEN Id % 3 = 0 THEN 'Idea'
                               WHEN Id % 5 = 0 THEN 'Jeans'
                               END


ALTER TABLE #fulltextindexesarestupid 
ADD LessBad AS CONVERT(BIT, CASE WHEN StopAbusingFeatures LIKE '%Bad%' THEN 1
                    WHEN StopAbusingFeatures LIKE '%Idea%' THEN 1
                    ELSE 0 END)

CREATE UNIQUE NONCLUSTERED INDEX ix_whatever ON #fulltextindexesarestupid (LessBad, Id)

การสืบค้นที่อ้างอิงจากคอลัมน์ที่ไม่มีการยืนยันจะทำให้เรามีแผน 'ใช้ดัชนี' และทุกอย่าง :)

SELECT COUNT(*)
FROM #fulltextindexesarestupid AS f
WHERE LessBad = 1

ถั่ว


-3

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

ฉันไม่เห็นด้วยกับวิธีแก้ปัญหาเช่นกัน แต่ฉันไม่แน่ใจว่าจะทำสิ่งนี้ได้ดีขึ้นใน SQL Server มาสร้างข้อมูลของเขาสำหรับ PostgreSQL กันเถอะ - มันก็ดีกว่าที่สร้างใน PostgreSQL ด้วย

CREATE TABLE fulltextindexesarestupid
AS
  SELECT
    id,
    CASE WHEN Id % 15 = 0 THEN 'Bad'
      WHEN Id % 3 = 0 THEN 'Idea'
      WHEN Id % 5 = 0 THEN 'Jeans'
    END AS StopAbusingFeatures
  FROM generate_series(1,1000000) AS id;

ตอนนี้สิ่งที่คุณต้องการคือประเภท enum

CREATE TYPE foo AS ENUM ('Bad', 'Idea', 'Jeans');

ALTER TABLE fulltextindexesarestupid
  ALTER StopAbusingFeatures
  SET DATA TYPE foo
  USING StopAbusingFeatures::foo;

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

SELECT *
FROM fulltextindexesarestupid
WHERE StopAbusingFeatures = 'Bad';

สิ่งนี้มีผลกระทบ

  1. ปกปิดความจริงที่ว่าคุณเป็นประเภทที่ระบุ ความซับซ้อนนั้นถูกห่อหุ้มในประเภทและซ่อนจากผู้ใช้
  2. มันยังทำการบำรุงรักษาในประเภทเหล่านั้นในประเภท
  3. มันเป็นมาตรฐาน
  4. มันไม่ได้ขยายขนาดแถว

คุณจะพยายามเพิ่มประสิทธิภาพการเปรียบเทียบสตริง แต่อนิจจาฉันไม่แน่ใจด้วยซ้ำว่า sp_BlitzErik จะได้รับคำตอบที่ได้รับจากรหัสในข้อเสนอแนะอย่างไร

like '%rock%' or
like '%paper%' or
like '%scisor%' or
like '%car%' or
like '%pasta%'

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

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