Помогите мне оптимизировать сложную логику на SQL - PullRequest
1 голос
/ 21 марта 2011

Сначала я попытаюсь (со своим плохим английским языком) объяснить, что у меня есть и что мне нужно иметь

У меня есть список событий по временной шкале.

Событиеэто некоторый дискретный сигнал 1/0, который происходит через некоторое время и имеет некоторую длительность.

мой список событий выглядит как

Rectime - start event time
Col - event name
ChangedDate - end event time
InitalValue - event message
Value - event state 1/0

И эти события могут вызывать некоторые сложные события, если они есть Событие A1 равно 1, A2 равно 0 или A5 равно 1 в одно и то же время - Например,

моя сложная структура событий (инцидентов)это:

[ID] - just ID
[Name] - just Name 
[SQL] - here is list of event names with logics alike ***(A1 AND NOT A2) OR A5***
[Message] - event message

Мне нужно не пропустить ни одного возможного изменения, поэтому я, когда происходит какое-то событие, я ищу сложные события, которые могут измениться, но чтобы узнать, изменилось ли это сложные события, мне нужно знать одругое зависит от этого сложного события, поэтому следующим шагом будет получение всех зависимых событий и их состояний 1/0.Вот моя попытка:

With DependencedIncidents AS -- Get all dependenced Incidents from this Event
(
    SELECT INC.[RecTime],INC.[SQL] AS [str] FROM
    (
        SELECT A.[RecTime] As [RecTime],X.[SQL] As [SQL] FROM [EventView] AS A 
        CROSS JOIN [Incident] AS X
            WHERE
                patindex('%' + A.[Col] + '%', X.[SQL]) > 0
    ) AS INC
)
, DependencedEvents AS -- Split SQL string to get dependeced Events for each dependeced Incident
(
    select distinct word AS [Event] , [RecTime]
    from
    (
        select v.number, t.[RecTime] As [RecTime],
            substring(t.str+')',
                      v.number+1,
                      patindex('%[() ]%',
                               substring(t.str+')',
                                         v.number+1,
                                         1000))-1) word
        from DependencedIncidents AS t
        inner join master..spt_values v on v.type='P'
          and v.number < len(t.str)
          and (v.number=0 or substring(t.str,v.number,1) like '[() ]')
    ) x
    where word not in ('','OR','AND')
)
, EventStates AS -- Dependeced events with their states 1/0
(
    Select D.[RecTime], D.[Event], X.[Value]
    From [DependencedEvents] AS D
    LEFT JOIN [EventView] AS X 
        ON X.Col = D.[Event]
        AND D.[Rectime] >= X.[Rectime]
        AND D.[Rectime] <= X.[ChangedDate]
)

select * from EventStates
order by [RecTime]

И она работает очень-очень медленно, мне нужна серьезная оптимизация, если это возможно.

Самая медленная (95% времени) часть -

LEFT JOIN [EventView] AS X 
    ON X.Col = D.[Event]
    AND D.[Rectime] BETWEEN X.[Rectime] AND  X.[ChangedDate]

возможно, я здесь что-то не так делаю ...

Я просто хочу проверить значение D. [Event] из EventView за это время D. [Rectime] ...

просмотр событий добавлен по запросам комментариев:

ALTER VIEW [dbo].[EventView] AS
            (SELECT RecTime, ChangedDate, ( 'Alarm' + CAST(ID as nvarchar(MAX)) ) AS Col, InitialValue, Value FROM [dbo].[Changes]
                WHERE InitialValue <> '')
            UNION ALL
            SELECT RecTime, ChangedDate, Col, InitialValue, Value FROM [dbo].[XDeltaIntervals]
            UNION ALL
            SELECT RecTime, ChangedDate, Col, InitialValue, Value FROM [dbo].[ActvXDeltaIntervals]

Ответы [ 3 ]

2 голосов
/ 21 марта 2011

Я думаю, что это должно быть примерно одинаково:

SELECT
  ev.Rectime,
  ev.Event,
  ev2.Value
FROM EventView AS ev
  INNER JOIN Incident i
    ON PATINDEX('%' + ev.Col + '%', i.SQL) > 0
  LEFT JOIN EventView ev2
    ON ev.Col = ev2.Col AND ev.Rectime BETWEEN ev2.Rectime AND ev2.ChangedDate

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

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

1 голос
/ 21 марта 2011

Ну, одна из самых основных концепций хранения реляционных данных - это

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

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

0 голосов
/ 23 марта 2011

Я думаю, что самая медленная часть происходит из определения EventView:

SELECT ... ( 'Alarm' + CAST(ID as nvarchar(MAX)) ) AS Col, ...

Соединение с таким вычисленным полем вызывает неприятное снижение производительности.

Не можете ли вы:

  • запись (Col =) Alarm + ID непосредственно в таблицу изменений или
  • обновление Alarm + ID по триггеру или
  • использование индексированного представления для расчета Alarm + ID или
  • используйте временную таблицу для хранения Alarm + ID или, по крайней мере,
  • не используйте nvarchar (MAX), а что-то вроде nvarchar (10) (если это меняет план запроса)

?

...