0

0

如何优化SQL中的LIKE查询?使用全文索引替换通配符查询提升性能

雪夜

雪夜

发布时间:2025-08-26 18:48:01

|

889人浏览过

|

来源于php中文网

原创

使用全文索引替代LIKE '%关键词%'查询可显著提升性能,因其基于倒排索引实现高效检索,避免全表扫描,同时支持词干提取、同义词、相关性排序等高级功能,适用于SQL Server、MySQL和PostgreSQL等主流数据库。

如何优化sql中的like查询?使用全文索引替换通配符查询提升性能

优化SQL中的

LIKE
查询,尤其是当通配符
%
出现在搜索模式开头时(例如
LIKE '%关键词%'
),最有效且推荐的方法是使用全文索引(Full-Text Index)来替代传统的通配符查询。这种方法能显著提升查询性能,将原本可能导致全表扫描的低效操作,转变为基于倒排索引的高效文本检索。

当我们谈到SQL查询优化,

LIKE
操作符,特别是那种通配符
%
放在开头的模式,比如
LIKE '%关键词%'
,几乎是性能杀手。它通常会强制数据库进行全表扫描,即使有索引也可能无法有效利用。我的经验告诉我,很多时候,这种模糊查询的需求,其实更适合用全文索引(Full-Text Index)来解决。

全文索引的工作原理与普通B树索引完全不同。它不是按字段值的顺序存储,而是将文本内容拆分成独立的词(token),并记录每个词出现在哪个文档(行)的哪个位置。这就像书的末尾的索引,你能快速找到某个词在哪几页出现过。

实现上,不同数据库系统有各自的全文索引方案:

  • SQL Server: 需要安装Full-Text Search组件,然后创建全文目录(Full-Text Catalog)和全文索引。

    -- 假设我们有一个Products表,想对ProductName字段进行全文搜索
    -- 1. 创建全文目录 (如果还没有)
    CREATE FULLTEXT CATALOG ProductCatalog AS DEFAULT;
    
    -- 2. 创建全文索引
    CREATE FULLTEXT INDEX ON Products(ProductName LANGUAGE 'Chinese')
    KEY INDEX PK_Products -- 你的表主键索引名,替换成实际的主键索引名
    ON ProductCatalog
    WITH CHANGE_TRACKING AUTO;

    查询时,使用

    CONTAINS
    FREETEXT

    -- 替换 LIKE '%手机%'
    SELECT ProductID, ProductName
    FROM Products
    WHERE CONTAINS(ProductName, '手机');
    
    -- 多个关键词,类似 AND 关系
    SELECT ProductID, ProductName
    FROM Products
    WHERE CONTAINS(ProductName, ' "智能" AND "手机" ');
  • MySQL (InnoDB): 从MySQL 5.6开始,InnoDB存储引擎支持全文索引。

    -- 1. 创建全文索引
    ALTER TABLE articles ADD FULLTEXT(title, body);
    -- 或者在创建表时定义
    CREATE TABLE articles (
        id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        title VARCHAR(200),
        body TEXT,
        FULLTEXT (title, body)
    ) ENGINE=InnoDB;

    查询时,使用

    MATCH AGAINST

    -- 替换 LIKE '%MySQL%'
    SELECT id, title, body
    FROM articles
    WHERE MATCH(title, body) AGAINST('MySQL');
    
    -- 布尔模式,更灵活,例如搜索包含MySQL但不包含InnoDB的
    SELECT id, title, body
    FROM articles
    WHERE MATCH(title, body) AGAINST('+MySQL -InnoDB' IN BOOLEAN MODE);
  • PostgreSQL: 使用

    tsvector
    tsquery
    类型,结合
    GIN
    GIST
    索引。

    -- 1. 添加tsvector列,用于存储文本向量
    ALTER TABLE products ADD COLUMN textsearchable_index_col tsvector;
    
    -- 2. 创建触发器,在数据插入或更新时自动更新tsvector列
    CREATE FUNCTION products_tsvector_trigger() RETURNS trigger AS $$
    BEGIN
        NEW.textsearchable_index_col :=
            to_tsvector('chinese', NEW.product_name || ' ' || NEW.description); -- 假设对product_name和description字段进行索引
        RETURN NEW;
    END
    $$ LANGUAGE plpgsql;
    
    CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
        ON products FOR EACH ROW EXECUTE FUNCTION products_tsvector_trigger();
    
    -- 3. 创建GIN索引,加速tsvector列的查询
    CREATE INDEX products_tsvector_idx ON products USING GIN (textsearchable_index_col);

    查询时,使用

    @@
    操作符:

    陌言AI
    陌言AI

    陌言AI是一个一站式AI创作平台,支持在线AI写作,AI对话,AI绘画等功能

    下载
    -- 替换 LIKE '%苹果%'
    SELECT product_id, product_name
    FROM products
    WHERE textsearchable_index_col @@ to_tsquery('chinese', '苹果');

通过这种方式,查询不再是逐行匹配字符串,而是利用高度优化的倒排索引,即便数据量巨大,也能在毫秒级内返回结果。这不仅仅是性能的提升,更是查询能力的一次升级,因为全文索引通常还支持词干提取、同义词、相关性排序等高级功能。

为什么传统的LIKE '%keyword%'查询效率低下?深入剖析其性能瓶颈

说实话,每次看到

LIKE '%关键词%'
这样的查询出现在生产环境的慢查询日志里,我都会本能地皱眉。它慢,不是偶然,而是其工作机制决定的。我们都知道,数据库中的B-tree索引是提升查询速度的利器,它将数据按序存储,让查找变得像翻字典一样快。但问题就出在这里:B-tree索引是基于前缀匹配的。

想象一下,你有一本按姓氏首字母排序的电话簿。如果你想找所有姓“张”的人,那很容易,直接翻到“Z”开头的页面就行。这就是

LIKE '张%'
能利用索引的原因。但如果你想找名字里包含“小明”的人,而你不知道他姓什么,你总不能从头到尾把电话簿每一页都翻一遍吧?这就是
LIKE '%小明%'
的困境。

当通配符

%
出现在搜索模式的开头时,数据库的查询优化器就傻眼了。它无法预测哪个词会包含这个子串,所以它唯一的选择就是:全表扫描(Full Table Scan)。它会一行一行地读取数据,然后对每一行的指定列进行字符串匹配。数据量小的时候可能不明显,一旦表里有几十万、上百万甚至更多行数据,这种操作就会迅速耗尽I/O资源、CPU,并可能导致长时间的表锁,直接影响到并发性能。

即使在某些情况下,数据库可能会尝试使用一些特殊的索引策略,比如在PostgreSQL中可能利用

pg_trgm
模块创建
GIN
GIST
索引来加速部分
LIKE
查询,但这并非所有数据库的默认行为,也不是解决所有模糊匹配问题的银弹。所以,从根本上理解,
LIKE '%keyword%'
的低效在于其无法有效利用大多数关系型数据库默认的B-tree索引结构,导致计算成本随着数据量的增长而呈线性甚至指数级上升。

全文索引相比传统LIKE查询有哪些核心优势?不仅仅是速度

在我看来,全文索引的引入,不仅仅是解决了

LIKE
查询慢的问题,它更像是一次搜索能力的“维度升级”。它的优势远不止于速度。

首先,压倒性的性能优势是显而易见的。就像前面提到的,全文索引通过构建倒排索引,将查找从“大海捞针”变成了“按图索骥”。当你的查询是

LIKE '%手机%'
时,数据库可能要遍历百万行;而使用全文索引,它直接查找到“手机”这个词对应的文档ID列表,然后直接取回这些文档,这个过程通常是毫秒级的。这种效率上的飞跃,对于用户体验和系统吞吐量来说,是质的提升。

其次,更智能、更丰富的搜索功能是传统

LIKE
望尘莫及的。

  • 词干提取(Stemming):比如你搜索“running”,它也能匹配到“run”、“runs”。这在自然语言处理中非常重要,让搜索结果更全面。
  • 同义词(Synonyms):你可以配置“手机”和“移动电话”是同义词,用户搜其中一个,都能找到相关内容。
  • 停用词(Stop Words):像“的”、“是”、“一个”这类常见但无意义的词,全文索引会自动忽略,避免它们干扰搜索结果的相关性。
  • 相关性排序(Relevance Ranking):全文索引通常会根据词频、词的位置等因素,给搜索结果一个相关性分数,让你能将最匹配的结果排在前面,这对于用户来说太重要了。传统
    LIKE
    只能告诉你“有”或“没有”。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

683

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

323

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

348

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1096

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

358

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

697

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

577

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

418

2024.04.29

AO3中文版入口地址大全
AO3中文版入口地址大全

本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

1

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Rust 教程
Rust 教程

共28课时 | 4.7万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 2.7万人学习

Go 教程
Go 教程

共32课时 | 4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号