在字符串中查找字符串 - SQL需要花费太多时间

时间:2011-06-22 04:28:12

标签: sql performance string sql-server-2008

我有两张桌子:

表1:CustomerEmails:

CREATE TABLE [dbo].[CustomerEmails](
    [id]            [int] IDENTITY(1,1) NOT NULL,
    [datecreated]   [datetime] NULL,
    [UID]           [nvarchar](250) NULL,
    [From]          [nvarchar](100) NULL,
    [To]            [nvarchar](100) NULL,
    [Subject]       [nvarchar](max) NULL,
    [Body]          [nvarchar](max) NULL,
    [Dated]         [datetime] NULL,
 CONSTRAINT [PK_CustomerEmails] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
)

表2:CustomerEmailIds

CREATE TABLE [dbo].[CustomerEmailIds](
    [Email] [varchar](200) NULL
) ON [PRIMARY]

您可能在想我为什么不在表CustomerEmails中使用EmailId而不是使用电子邮件本身?我的意思是我可以将一列EmailId(INT)添加到表CustomerEmailIds&然后我可以引用该列而不是CustomerEmails.From& CustomerEmails.To?伙计问题是表CustomerEmails被其他一些应用程序使用&该应用程序只是跟踪通过OutLook发送/接收的电子邮件。表CustomerEmailIds有客户电子邮件&这些电子邮件从我正在处理的应用程序进入系统。

因此,表CustomerEmails有7,00,000多条记录,而表CustomerEmailIds有1,00,000多条记录。

我需要根据CustomerEmailIds表中的电子邮件找到来自CustomerEmails表的电子邮件。

我正在使用的查询是:

SELECT  
        e.*
FROM    CustomerEmails e 
WHERE   EXISTS 
        (
            SELECT  Email 
            FROM    CustomerEmailIds c 
            WHERE   ( ISNULL(e.[From],'') + '/' + ISNULL(e.[To],'') ) LIKE  '%'+c.Email+'%' 
        )

Some facts:
1- I am using SQL Server 2008
2- Sorry guys, i forgot to mention that the CustomerEmails.**To** can contains multiple comma separated emails like: email1@yahho.com,email2@yahho.com,email3@yahho.com
3- Because of the fact2 the c.Cs3Emails+'%' OR to= c.Cs3Emails will not list the desired results that's why i am using '%'+c.Cs3Emails+'%'

最新调查结果: 伙计上面的查询返回错误的结果.....&我不知道为什么?

但是下面的查询工作正常:

SELECT  
    e.*
FROM    CustomerEmails e 
WHERE   (ISNULL(e.[From],'') + '/' + ISNULL(e.[To],'')) LIKE  '%email1@gmail.com%' 

5 个答案:

答案 0 :(得分:3)

雅各布, 查询中的where子句永远不会使用索引。 这是因为有两个问题:

1)你正在进行字符串连接以进行比较

ISNULL(e.[From],'') + '/' + ISNULL(e.[To],'') ) 

2)你喜欢

后两端使用外卡
LIKE  '%'+c.Cs3Emails+'%'

为了优化,我建议这样做:

1)您创建另一列以存储电子邮件的连接值。 额外的存储,但这将使您免于运行缓慢。 然后,您可以在该列上创建索引以加快速度。

2)您是否可以更改类似条件?

LIKE c.Cs3Emails+'%'

从开头删除%可能会使用索引(如果c.Cs3Emails上有任何内容)

希望这有帮助

答案 1 :(得分:2)

这部分查询:

WHERE   ( ISNULL(e.[From],'') + '/' + ISNULL(e.[To],'') ) LIKE  '%'+c.Cs3Emails+'%'

强制执行全表扫描,因为它使用WHERE子句中的函数,并且因为类似'%....%' - 开头的%符号。你可以重写那个部分来使用字段/常量吗?

您应该让您的查询在索引字段中受益 - 例如,如果您在字段c.Cs3Emails上有索引,那么您的查询应该看起来像

WHERE c.Cs3Emails = 'some_value_here'

some_value_here值不应该是函数输出的结果(如果这是可能的话)

即使您的查询看起来像

WHERE c.Cs3Emails = 'some_value_here%' 

可以使用索引,但不能使用

WHERE c.Cs3Emails = '%some_value_here%'

因为在这里,就像你会试着在名字的第二个字母之后找到电话簿。

尝试详细了解database indexes以及如何使用它们

此外,我认为您可以重写您的查询:

SELECT  
        e.*
FROM    Emails e 
WHERE   EXISTS 
        (
            SELECT  Cs3Emails 
            FROM    Cs3EmailsForPurge c 
            WHERE   e.From = c.Cs3Emails OR e.To = c.Cs3Emails             
        )

请尝试此查询,看看它是否返回与您相同的结果

如果我的查询返回相同的结果集并且性能没有提高,请在字段Emails.From上添加索引,在Emails.To上添加索引。这将改善您的查询执行时间。

答案 2 :(得分:2)

这个查询背后的想法是有缺陷的。我知道您正在尝试使用跟踪编号将消息链接在一起,可能在主题行中,但这应该起作用的方式是,当电子邮件导入数据库时​​,应找到他们的跟踪编号,然后将其提取到自己的领域。通过这种方式,您可以为每次导入付出轻微的打击,但在查询数据时可以获得巨大的好处。

我建议您更新当前数据并重写导入。该查询不会再获得更高的性能。

答案 3 :(得分:0)

答案 4 :(得分:0)

好人们首先看一下返回错误结果的查询:

SELECT  
        e.*
FROM    CustomerEmails e 
WHERE   EXISTS 
        (
            SELECT  Email 
            FROM    CustomerEmailIds c 
            WHERE   ( ISNULL(e.[From],'') + '/' + ISNULL(e.[To],'') ) LIKE  '%'+c.Email+'%' 
        )

此查询没有问题,问题是CustomerEmailIds表中的某些电子邮件是无效的电子邮件('。','@','0',' - ')&这就是为什么查询返回存在这些无效电子邮件的所有CustomerEmails的原因。

感谢Kev Riley帮助我的人找出了这个问题的原因here