2012-05-13 2 views
1

У меня есть функция, которая берет две строки с разделителями и возвращает количество общих элементов.оптимизировать sql-функцию для получения общих элементов

Основной код функции (@intCount ожидаемое возвращаемое значение)

SET @commonCount = (select count(*) from (
    select token from dbo.splitString(@userKeywords, ';') 
    intersect 
    select token from dbo.splitString(@itemKeywords, ';')) as total) 

, где splitString использует время цикла и CHARINDEX разделить строку в разделителями токенов и вставляет его в таблицу.

Проблема, с которой я сталкиваюсь, заключается в том, что это только процессы со скоростью около 100 строк в секунду и размером моего набора данных, это займет около 8-10 дней.

Размер двух строк может составлять до 1500 символов.

Есть ли в любом случае я могу достичь этого достаточно быстро, чтобы его можно было использовать?

+0

Это что-то, что вам нужно для запуска все время, или это одноразовые усилия? – dasblinkenlight

+0

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

ответ

1

Проблема с производительностью, вероятно, является комбинацией курсора (для цикла while) и пользовательской функции.

Если одна из этих строк является постоянным (например, пункт ключевых слов), вы можете искать для каждого из них независимо друг от друга:

select * 
from users u 
where charindex(';'+<item1>+';', ';'+u.keywords) > 0 
union all 
select * 
from users u 
where charindex(';'+<item2>+';', ';'+u.keywords) > 0 union all 

Альтернативно, подход, основанный на набор может работать, но вы должны нормализовать данные (для начала подключите данные в правильном формате). То есть, вы хотите таблицу, которая имеет:

userid 
keyword 

И еще, что имеет

itemid 
keyword 

(если есть различные типы элементов В противном случае это просто список ключевых слов.).

Тогда ваш запрос будет выглядеть следующим образом:

select * 
from userkeyword uk join 
    itemkeyword ik 
    on uk.keyword = ik.keyword 

И SQL двигатель будет выполнять свою магию.

Теперь, как вы можете создать такой список? Если у вас есть только несколько ключевых слов для каждого пользователя, то вы можете сделать что-то вроде:

with keyword1 as (select u.*, charindex(';', keywords) as pos1, 
         left(keywords, charindex(';', keywords)-1) as keyword1 
        from user u 
        where charindex(';', keywords) > 0 
       ), 
    keyword2 as (select u.*, charindex(';', keywords, pos1+1) as pos2, 
         left(keywords, charindex(';', keywords)-1, pos1+1) as keyword2 
        from user u 
        where charindex(';', keywords, pos1+2) > 0 
       ), 
     ... 
select userid, keyword1 
from keyword1 
union all 
select userid, keyword2 
from keyword2 
... 

Чтобы получить максимальное количество элементов в itemKeyWords, вы можете использовать следующий запрос:

select max(len(Keywords) - len(replace(Keywords, ';', ''))) 
from user 
+0

Я подумываю о том, чтобы идти на основе таблицы. Данные, которые я получил, были в плоских файлах в том формате, который я загрузил в таблицы. Они не нормализовались и составят около 2-3 концертов. – randomThought

+0

Я бы использовал powershell для разделения данных, а затем загрузил их в нормализованном формате. Если у вас уже есть данные в таблице, попробуйте подход в письме. Это может работать лучше, чем вы ожидаете, особенно если вы работаете на многопроцессорной машине. Ваш оригинальный подход, вероятно, сериализует запрос, поэтому он не использует все ваше оборудование. –