Найти строку внутри строки - SQL занимает слишком много времени - PullRequest
0 голосов
/ 22 июня 2011

У меня есть две таблицы:

Таблица 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]

Возможно, вы думаете, почему я не использую EmailId в таблице CustomerEmails вместо использования самих электронных писем?Я имею в виду, что я могу добавить столбец EmailId (INT) к таблице CustomerEmailIds, а затем я могу ссылаться на этот столбец вместо CustomerEmails.From & CustomerEmails.To ??Ребята, проблема в том, что таблица CustomerEmails используется каким-либо другим приложением, и это приложение просто отслеживает электронные письма, отправленные / полученные через OutLook.В таблице CustomerEmailIds содержатся электронные письма клиентов, и эти сообщения поступают в систему из приложения, над которым я работаю.

Таким образом, в таблице CustomerEmails содержится более 7 000 000 записей, в то время как в таблице CustomerEmailIds содержится более 1 000 000 записей.1016 * Мне нужно выяснить электронные письма из таблицы CustomerEmails, основываясь на электронных письмах в таблице CustomerEmailIds.

Я использую следующий запрос:

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 ]

3 голосов
/ 22 июня 2011

Якуб, Предложение where в вашем запросе никогда не будет использовать индекс. Это из-за 2 проблем:

1) вы делаете конкатенацию строк на лету для сравнения

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

2) вы используете подстановочный знак на обоих концах после

LIKE  '%'+c.Cs3Emails+'%'

Для оптимизации я предлагаю следующее:

1) Вы создаете еще один столбец для хранения объединенного значения электронных писем. Дополнительное хранилище, но это избавит вас от медленной работы. Затем вы можете создать индекс для этого столбца, чтобы ускорить процесс.

2) Возможно ли, что вы изменили подобное условие?

LIKE c.Cs3Emails+'%'

При удалении % с начала может использоваться индекс (если он есть на c.Cs3Emails)

Надеюсь, это поможет

2 голосов
/ 22 июня 2011

идея этого запроса ошибочна.Я понимаю, что вы пытаетесь объединить сообщения в цепочку, используя номер отслеживания, возможно, в строке темы, но способ, которым это должно работать, заключается в том, что, поскольку электронные письма импортируются в базу данных, их номер отслеживания должен быть найден и затем извлеченсвое собственное поле.при этом вы вносите небольшой удар в каждый импорт, но получаете огромные преимущества при запросе ваших данных.

Я бы предложил вам обновить текущие данные и переписать импорт.этот запрос не станет более производительным.

2 голосов
/ 22 июня 2011

Эта часть запроса:

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%'

Потому что здесь, это как если бы вы пытались найти в телефонной книге после второй буквы имени.

Попробуйте прочитать больше о индексы базы данных и способы их использования

Кроме того, я думаю, что вы можете переписать свой запрос, например:

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.Это улучшит время выполнения вашего запроса.

0 голосов
/ 23 июня 2011

Ну, ребята, сначала посмотрите на запрос, который возвращает неправильные результаты:

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

В этом запросе нет проблем, проблема в том, что некоторые электронные письма в таблице CustomerEmailIds недействительные электронные письма ('.', '@', '0', '-') и именно поэтому запрос возвращает все сообщения CustomerEmail, где существуют эти недействительные электронные письма.

Спасибо Кеву Райли ! людям, которые помогли мне выяснить причину этой проблемы здесь !

0 голосов
/ 22 июня 2011
...