2008-12-01 4 views
3

У меня есть таблица данных временного ряда, из которых мне нужно найти все столбцы, содержащие хотя бы одно ненулевое значение за данный период времени. До сих пор я использую следующий запрос:SQL find non-null columns

select max(field1),max(field2),max(field3),... 
    from series where t_stamp between x and y 

Затем я проверяю каждое поле результата, если он содержит ненулевое значение.

Таблица содержит около 70 столбцов, а период времени может содержать> 100 тыс. Записей.

Интересно, если есть более быстрый способ сделать это (используя только стандартный sql).

EDIT: К сожалению, реорганизация дизайна стола для меня не является вариантом.

ответ

4

Операция EXISTS может быть быстрее, так как она может остановить поиск, как только найдет любую строку, соответствующую критериям (по сравнению с используемым MAX). Это зависит от ваших данных и от того, насколько разумным является ваш SQL-сервер. Если в большинстве ваших столбцов имеется высокая скорость ненулевых данных, этот метод быстро найдет строки, и он должен работать быстро. Если ваши столбцы в основном имеют значения NULL, ваш метод может быть быстрее. Я бы дал им оба выстрела и посмотреть, как они оптимизированы и как они работают. Также имейте в виду, что производительность может измениться со временем, если распределение ваших данных значительно изменится.

Кроме того, я тестировал это только на MS SQL Server. Мне не приходилось кодировать строгий ANSI-совместимый SQL в течение года, поэтому я не уверен, что это полностью общий.

SELECT 
    CASE WHEN EXISTS (SELECT * FROM Series WHERE t_stamp BETWEEN @x AND @y AND field1 IS NOT NULL) THEN 1 ELSE 0 END AS field1, 
    CASE WHEN EXISTS (SELECT * FROM Series WHERE t_stamp BETWEEN @x AND @y AND field2 IS NOT NULL) THEN 1 ELSE 0 END AS field2, 
... 

EDIT: Просто для уточнения, метод MAX может быть быстрее, так как он может определить эти значения за один проход через данные. Теоретически, метод здесь также может быть и, возможно, с меньшим, чем полный проход, но ваш оптимизатор может не признать, что все подзапросы связаны, поэтому он может делать отдельные проходы для каждого. Это все еще может быть быстрее, но, как я уже сказал, это зависит от ваших данных.

0

Редактировать: Я думаю, что неправильно понял вопрос ... это даст вам все строки с ненулевым значением. Я оставлю его здесь, если это поможет кому-то, но это не ответ на ваш вопрос. Благодаря @Pax

Я думаю, что вы хотите использовать COALESCE:

SELECT ... WHERE COALESCE(fild1, field2, field3) IS NOT NULL

+0

Он ищет, чтобы найти столбцы с хотя бы одним NULL, ваше решение дает NULL для строки, если все они NULL. Я не думаю, что это помогает с обнаружением отдельных столбцов. – paxdiablo 2008-12-01 12:11:46

+0

@Pax: перечитайте заявление о проблеме. Он хочет найти NON-null столбцы, поэтому фильтрация строк даст минимум. – GalacticCowboy 2008-12-01 12:23:05

1

Было бы быстрее, с другой конструкцией стола:

create table series (fieldno integer, t_stamp date); 

select distinct fieldno from series where t_stamp between x and y; 

Имея таблицу с 70 "подобных" полей обычно не является хорошей идеей.

0

Для начала это очень плохая идея со стандартным SQL, так как не все типы СУБД сортируются с последними NULL.

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

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

После редактирования вопроса: если дизайн таблицы рефакторинга не является вариантом, ваше решение, вероятно, является лучшим, особенно если у вас есть индексы на всех 70 столбцах.

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

0
select count(field1),count(field2),count(field3),... 
    from series where t_stamp between x and y 

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

0

Попробуйте это:

SELECT CASE WHEN field1 IS NOT NULL THEN '' ELSE 'contains null' END AS field1_stat, 
     CASE WHEN field2 IS NOT NULL THEN '' ELSE 'contains null' END AS field2_stat, 
... for every field to be checked 
FROM series 
WHERE foo IN bar 
GROUP BY CASE WHEN field1 IS NOT NULL THEN '' ELSE 'contains null' END, 
     CASE WHEN field2 IS NOT NULL THEN '' ELSE 'contains null' END 
... etc 

Это даст вам резюме по сочетанию «обнуляется» полей в таблице

1

Когда вы говорите, «более быстрый способ сделать это», если вы имеете в виду более быстрый способ для запроса бежать, то да, вот как это сделать: разбить его на один запрос на столбец:

select top 1 field1 from series where t_stamp between x and y and field1 is not null

select top 1 field2 from series where t_stamp between x and y and field2 is not null

select top 1 field3 from series where t_stamp between x and y and field3 is not null

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

1

Как насчет этого ... Вы запрашиваете список имен полей, которые вы можете выполнить итерацией.

select 'field1' as fieldname from series 
    where field1 is not null and t_stamp between x and y 
UNION 
select 'field2' from series where field2 is not null 
... etc 

Тогда у вас есть набор записей, который будет содержать только строковое имя полей, которые не являются нулевыми. Затем вы можете перебрать этот набор записей, чтобы создать реальный запрос как динамический SQL и игнорировать поля, у которых нет данных. Поле «select» 2 '' не будет возвращать строку, если нет критериуса, соответствующего предложению where.