2015-11-16 2 views
1

Я недавно унаследовал некоторый код, который выглядит примерно так.Группируйте только по некоторым столбцам?

SELECT DISTINCT 
    field1, field2...(600 lines later)... field99 
FROM 
    MillionRowTable 
WHERE 
    EntryDate > @LastWeek 

С distinct, это занимает несколько часов и замки других людей, потому что она использует 100% от центрального процессора. Без четкости это намного быстрее, но у него есть дубликаты.

Однако я отметил, что если поле1 и поле2 совпадают с полем1 и полем2 в другой строке, то я уже знаю, что они дубликаты, и мне не нужно будет проверять какой-либо другой столбец. Есть ли способ группировать только эти 2 столбца, чтобы я мог избежать дубликатов и 4 часа работы?

+1

1. group by field1, 2 и max (другие поля) 2. row_number() over (partiotion by fileld1, 2) .. где rn = 1 –

+0

Итак, вы используете 'DISTINCT' на 600 столбцах? Я полагаю, что большую часть времени тратится на сортировку записей перед применением оператора DISTINCT. Как насчет вставки без 'DISTINCT' в временную таблицу и отсортировать ее там? –

+0

Вы попробовали? Если вы хотите использовать GROUP, то каждый столбец, который не является частью оператора GROUP BY, должен быть агрегирован. В вашем примере это не сработает, потому что вы не можете Агрегировать по полю99, правильно? Или вы хотите найти повторяющиеся строки? – CPMunich

ответ

0

Обычный метод агрегировать с MAX() или MIN():

SELECT field1, field2, MAX(field3) AS field3,...(600 lines later)... MAX(field99) AS field99 
FROM MillionRowTable 
WHERE EntryDate>@LastWeek 
GROUP BY field1, field2 

Обратите внимание, что не все типы данных поддерживают MAX() и MIN() (BIT не делает, к примеру), и это не может улучшить производительность на всех.

Также работает второй метод с ROW_NUMBER(), но я не уверен, насколько хорошо он будет работать с таким большим набором данных.

;WITH CTE AS (
    SELECT field1, field2...(600 lines later)... field99 
     , ROW_NUMBER() OVER (PARTITION BY field1, field2 ORDER BY (SELECT 1)) rn 
    FROM MillionRowTable 
    WHERE EntryDate > @LastWeek 
) 
SELECT field1, field2...(600 lines later)... field99 
FROM CTE 
WHERE rn = 1; 

Обратите внимание, что вы сусло ORDER BY что-то с ROW_NUMBER(). (SELECT 1) - это нечто непреложное.

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

+0

Существует фактическая логика, содержащаяся в этом 600 строк позже. Заявления о делах, подстроки, математика, конверты и т. Д. Я должен был сделать это яснее, прошу прощения. SInce есть эта логика, там я могу просто выбрать * из CTE? – lefeal

+0

@lefeal Я бы не 'SELECT *' для производственного кода. Я бы перечислил поля. –

Смежные вопросы