【问题标题】:Select LIKE '%string%', without FULL-TEXT-SEARCH in SQL Server在 SQL Server 中选择 LIKE '%string%',而不使用 FULL-TEXT-SEARCH
【发布时间】:2018-01-12 14:37:58
【问题描述】:
-- create table
CREATE TABLE dbo.Tests
(
    Id BIGINT NOT NULL IDENTITY,
    String NVARCHAR(100),
    StringReversed AS REVERSE(String),
    CONSTRAINT PK_Tests PRIMARY KEY (Id), 
)
CREATE NONCLUSTERED INDEX IX1 ON dbo.Tests(String)
CREATE NONCLUSTERED INDEX IX2 ON dbo.Tests(StringReversed)


-- populate table with 100k random strings (for testing)
DECLARE @I INT = 100000
WHILE @I > 0
BEGIN
    INSERT INTO Tests(String)
    SELECT CONVERT(varchar(36), NEWID())
    SET @I = @I - 1
END

-- how do i do a LIKE '%STRING%' search which uses the index?
SELECT String, StringReversed FROM Tests WHERE String LIKE '%0A7EB%'

SELECT String, StringReversed FROM Tests 
    WHERE String LIKE '0A7EB%' OR StringReversed LIKE 'BE7A0%'

你能帮我解决这个问题吗?我正在尝试实现一个全文搜索替代方案,以便能够执行 LIKE '%STRING%' WHERE 子句。

我不太确定这是否可能实现?让我们假设全文搜索是不可能的,我需要使用索引。

这是一个刺激问题,我们需要在字符串列中执行 LIKE '%search%'。我刚刚在这里读到:SQL Server: Index columns used in like? 我们可以做反向吗?

希望你能帮助我,非常感谢。

【问题讨论】:

  • 简单地说,你不能。当您有前导通配符时,您创建了一个 nonSARGable 谓词。想想看……你必须查看每一行才能知道它是否包含你要查找的字符串。
  • 你可以试试where CONTAINS(String, '0A7EB')只是出于好奇`
  • @voljko89: contains 仅适用于全文索引。
  • 不,您当前的查询不起作用,因为这两个子句都假定子字符串必须出现在字符串的开头或结尾(无论如何它们都是 100% 冗余的)。查看thisthisthis 了解潜在的三元组解决方案。
  • 我看不到你认为有什么问题的问题?但是正如@SeanLange 所说,LIKE '%search%' 不会使用索引,但这并不会阻止您使用它。如果您需要提高性能,请切换到Full Text Search

标签: sql sql-server full-text-search sql-like


【解决方案1】:

更新:我尝试了字符串片段方法。

-- create table
CREATE TABLE dbo.Tests
(
    Id BIGINT NOT NULL IDENTITY,
    String NVARCHAR(100),
    CONSTRAINT PK_Tests PRIMARY KEY (Id), 
)
GO

-- create table for Test String Fragments
CREATE TABLE dbo.TestStringFragments(
    Id BIGINT NOT NULL IDENTITY,
    TestId BIGINT NOT NULL,
    Fragment NVARCHAR(100),
    CONSTRAINT PK_TestStringFragments PRIMARY KEY (Id)
)
CREATE NONCLUSTERED INDEX IX_TestStringFragments_Fragment ON dbo.TestStringFragments(Fragment)
CREATE NONCLUSTERED INDEX IX_TestStringFragments_TestId ON dbo.TestStringFragments(TestId)
GO

-- create UDF to generate string fragments
CREATE FUNCTION dbo.CreateStringFragments(@input nvarchar(100))
RETURNS TABLE WITH SCHEMABINDING
AS
RETURN 
(
    WITH x(x) AS 
    (SELECT 1 UNION ALL SELECT x+1 FROM x WHERE x < (LEN(@input)))
    SELECT Fragment = SUBSTRING(@input, x, LEN(@input)) FROM x
)
GO

-- create trigger for the Tests table
CREATE TRIGGER dbo.Tests_MaintainStringFragments
ON dbo.Tests
FOR INSERT, UPDATE, DELETE
AS
BEGIN
    SET NOCOUNT ON

    DELETE TSF FROM dbo.TestStringFragments AS TSF
    INNER JOIN deleted ON TSF.TestId = deleted.Id

    INSERT dbo.TestStringFragments(TestId, Fragment)
    SELECT inserted.Id, fragments.Fragment
    FROM inserted 
    CROSS APPLY dbo.CreateStringFragments(inserted.String) AS fragments

END
GO

-- populate table with 100k random strings (for testing)
DECLARE @I INT = 100000
WHILE @I > 0
BEGIN
    INSERT INTO Tests(String)
    SELECT CONVERT(varchar(36), NEWID())
    SET @I = @I - 1
END

能够通过片段表复制 LIKE '%string%' 代码。

SELECT T.* FROM Tests T WITH(NOLOCK)
WHERE T.String LIKE '%CBB2%'

SELECT T.* FROM Tests T WITH(NOLOCK)
INNER JOIN TestStringFragments TSF WITH(NOLOCK) ON T.Id = TSF.TestId
where TSF.Fragment LIKE 'CBB2%'

我的新执行计划是第一个查询的 61%,第二个查询的 39%。我会检查 trigrams 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-13
    • 2013-05-26
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 2010-12-10
    相关资源
    最近更新 更多