代码之家  ›  专栏  ›  技术社区  ›  thatismatt

实体框架生成的用于字符串匹配的SQL

  •  7
  • thatismatt  · 技术社区  · 17 年前

    给定此针对EF数据上下文的LINQ查询:

    var customers = data.Customers.Where(c => c.EmailDomain.StartsWith(term))
    

    您希望它生成这样的SQL,对吗?

    SELECT {cols} FROM Customers WHERE EmailDomain LIKE @term+’%’
    

    实际上,它是这样做的:

    SELECT {cols} FROM Customer WHERE ((CAST(CHARINDEX(@term, EmailDomain) AS int)) = 1)
    

    你知道为什么吗?

    另外,将Where选择器替换为:

    c => c.EmailDomain.Substring(0, term.Length) == term
    

    它的运行速度快了10倍,但仍然会产生一些非常糟糕的SQL。

    注: linq to sql正确地将startswith转换为like term%,nhibernate有一个专用的likeexpression。

    5 回复  |  直到 11 年前
        1
  •  2
  •   Timothy Khouri    17 年前

    原因是,对于SQL来说,charindex执行起来要比喜欢的快得多,更干净。原因是,你 可以 有一些疯狂的“喜欢”条款。例子:

    SELECT * FROM Customer WHERE EmailDomain LIKE 'abc%de%sss%'
    

    但是,“charindex”函数(基本上是“indexof”)只处理查找一组字符的第一个实例…不允许使用通配符。

    所以,这是你的答案:)

    编辑:我只是想补充一点,我鼓励人们在SQL查询中使用charindex来查找不需要“like”的内容。尽管在SQL Server 2000中…“文本”字段可以使用 喜欢 方法,但不是charindex。

        2
  •  3
  •   Alex Burtsev    15 年前

    我不了解MS SQL Server,但是在SQL Server Compact上,比如“foo%”,比charindex快数千倍,如果您在seach列上有索引的话。现在我正坐着拔我的头发,如何强迫它像这样使用。

    http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/1b835b94-7259-4284-a2a6-3d5ebda76e4b

        3
  •  0
  •   edosoft    17 年前

    Like和Charindex的表现似乎差不多,所以这不应该是原因。见 here here 进行讨论。而且演员阵容也很奇怪,因为查林德克斯返回了一个int。

        4
  •  0
  •   mjallday    17 年前

    charindex返回第二个术语中第一个术语的位置。

    SQL以1开头作为第一个位置(0=未找到)

    http://msdn.microsoft.com/en-us/library/ms186323.aspx

    我不知道它为什么使用这种语法,但这就是它的工作原理

        5
  •  0
  •   semirturgay AMIT KANALA    11 年前

    我同意这样做不会更快,我从数据库中检索了数万行,其中有字母I的名字。不过,我发现您需要使用>而不是=。所以用

    {cols} FROM Customer WHERE ((CAST(CHARINDEX(@term, EmailDomain) AS int)) > 0)
    

    而不是

    {cols} FROM Customer WHERE ((CAST(CHARINDEX(@term, EmailDomain) AS int)) = 1)
    

    这是我的两个测试……

    select * from members where surname like '%i%'    --12 seconds
    
    select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) > 0)  --12 seconds
    
    select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) = 1)  --too few results