【问题标题】:SQL Server 2012 poor performance when selecting using LIKE from a large table从大表中选择使用 LIKE 时 SQL Server 2012 性能不佳
【发布时间】:2012-10-03 19:11:08
【问题描述】:

我有一个大约 1M 行的表,并针对它运行以下 SQL:

select * from E where sys like '%,141,%'

执行需要 2-5 秒(返回约 10 行),我需要它至少快 10 倍,这是 SQL Server 2012 可以实现的吗?

sys 值示例(sys 值长度范围为 5 到 1000 个字符):

1,2,3,7,9,10,11,12,14,17,28,29,30,33,35,37,40,41,42,43,44,45,46,47,48,50,51,53,55,63,69,
72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,97,109,110,111,113,117,
119,121,122,123,124,130,131,132,133,134,135,139,141,146

表的 DDL:

CREATE TABLE [dbo].[E](
    [o] [int] NOT NULL,
    [sys] [varchar](8000) NULL,
    [s] [varchar](8000) NULL,
    [eys] [varchar](8000) NULL,
    [e] [varchar](8000) NULL,
 CONSTRAINT [PK_E] PRIMARY KEY CLUSTERED 
(
    [o] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

【问题讨论】:

  • 请注意,如果您要查找的数字位于字符串的 first 或 last 位置,则您的代码将根本不起作用。
  • 是的,值应该以 ',' 开头和结尾。谢谢。

标签: tsql sql-server-2012 sqlperformance


【解决方案1】:

您的like 子句导致了全表扫描。

如果您想要此查询的即时性能,您将需要一个包含以下字段的一对多表:

E_Key  <-- Foreign Key, points to primary key of E table
sys    <-- Each record contains one number, not multiple numbers 
           separated by commas

然后您可以索引sys,并使用普通的 WHERE 子句。

【讨论】:

  • 由于大小而无法完成 - 我试过了,子表将有 1B 行,这使得它实际上不可查询。
  • 然后我会研究对结果集进行分区的方法,以便减少必须使用like 扫描的记录数。也许你有一个category 字段,你可以在上面使用WHERE?
  • @user1514042 在这个答案中设置它时的性能如何? E_Key 是否在聚集索引中?
  • 我假设您首先尝试在 没有 索引的情况下填充表,因为在每个 INSERT 上更新索引会减慢该过程。初始表填充只需发生一次。
  • @user1514042 你的意思是你的硬盘空间用完了?
【解决方案2】:

如果您无法更改表架构,您可以启用Full-Text search 并在表上创建全文索引,然后执行以下操作:

select * from E where CONTAINS(sys, ",141,")

【讨论】:

  • 有意思,我试试
  • 有趣的是-搜索条件不能包含','我应该使用转义字符吗?
  • 在这种情况下,您可能应该跳过在 sys 列中使用 , 作为分隔符,而是使用空格。而不是使用 CONTAINS(sys, "141"),如果我没记错的话,CONTAINS 在字符串中搜索单词。
  • 是的,我可以使用'|'相反,否则它会很快,非常感谢!
  • 搜索词中不需要逗号。全文搜索搜索单词(在标点之间的字符序列)。
【解决方案3】:

LIKE 运算符总是会变慢,因为这会强制 SQL Server 扫描每一行以查找您要查找的数据。下面是 LIKE 的替代方法,可能会更好一些(尽管仍会扫描数据)。

SELECT * FROM E WHERE CHARINDEX(',141,', sys) > 0

【讨论】:

  • 它的速度大约是以前的两倍,但感谢您的选择。
【解决方案4】:

我知道这是一篇较旧的帖子,但是...

如果您一心想在表中存储非规范化数据,请将其转换为 XML,以便您至少可以对其进行索引。

但是,最好的办法是通过将数据拆分为一对多查找表来规范化该数据(正如上面 robert Harvey 建议的那样)。

【讨论】:

  • 嗨,Jeff,我已经走了这条路——它导致了数千亿条记录,而这些记录根本无法使用 SQL 服务器来处理......
  • 嗯嗯。看看到目前为止的答案。 “全文搜索”。 “LIKE 会很慢”。罗伯特·哈维(迄今为止最被接受的答案)完全按照我的建议做了,而且速度绝对令人目眩。如果正确创建了表、数据和索引,则数百万行将毫无意义。在列中维护 CSV 信息几乎与在列中存储 XML 一样糟糕。 ;-) 数千亿行比存储 CSV 的数十亿行要好得多。
  • 完全同意,不幸的是原始数据和 csv 数据之间的比率可能是 1:100K,这使得保留原始数据变得不可能。
  • 啊...现在我明白了。你不是在谈论每个人。您只是在谈论您的特定实例/问题,对吗?为什么每个项目有 10 万个项目?有什么方法可以让我们稍微标准化一下数据吗?另外,每个项目有 100K 项目?您的原始帖子说您的“sys”值将是 5 到 1000 个字符。无论您多么努力,您都无法将 100k 个项目放入 1000 个字符中。甚至您的 DDL 每行也少于 100K。这里的实际要求是什么?
  • 可能是 100K,通常不到一千,但无论如何,在弄清楚性能影响后,我们采用了完全不同的设计。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-14
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多