Как создать представление из таблицы значений свойств в SQL - PullRequest
1 голос
/ 04 июня 2009

У меня есть таблица в SQL, которая имеет четыре столбца. Два из них - это столбцы свойств и значений, в которых хранятся показатели производительности для одного из наших серверов. Мы постоянно придумываем новые показатели производительности, и мы не хотели продолжать дорабатывать нашу схему, поэтому мы разработали таблицу таким образом.

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

По сути, я чувствую, что я делаю что-то действительно неправильно, но я не могу найти лучший способ решить проблему.

SELECT 
    astats.AQTORStatsID, 
    astats.ServerName, 
    astats.Remarks, 
    astats.StatsBeginDateTime, 
    astats.StatsEndDateTime,
    asi1.AQTORStatValue as 'QtCPU_Average',
    asi2.AQTORStatValue as 'QtCPU_TopQuintile',
    asi3.AQTORStatValue as 'QtCPU_TopOnePercent',
    asi4.AQTORStatValue as 'QtCl_Average',
    asi5.AQTORStatValue as 'QtCl_TopQuintile',
    asi6.AQTORStatValue as 'QtCl_TopOnePercent',
    asi7.AQTORStatValue as 'UpdPrcStd_Average',
    asi8.AQTORStatValue as 'UpdPrcStd_TopQuintile',
    asi9.AQTORStatValue as 'UpdPrcStd_TopOnePercent',
    asi10.AQTORStatValue as 'RcRsUPr_Average',
    asi11.AQTORStatValue as 'RcRsUPr_TopQuintile',
    asi12.AQTORStatValue as 'RcRsUPr_TopOnePercent'
FROM 
    tb_rAQTORStatsItem asi1
    INNER JOIN tb_rAQTORStatsItem asi2 ON asi1.AQTORStatsID = asi2.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi3 ON asi2.AQTORStatsID = asi3.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi4 ON asi3.AQTORStatsID = asi4.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi5 ON asi4.AQTORStatsID = asi5.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi6 ON asi5.AQTORStatsID = asi6.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi7 ON asi6.AQTORStatsID = asi7.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi8 ON asi7.AQTORStatsID = asi8.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi9 ON asi8.AQTORStatsID = asi9.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi10 ON asi9.AQTORStatsID = asi10.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi11 ON asi10.AQTORStatsID = asi11.AQTORStatsID
    INNER JOIN tb_rAQTORStatsItem asi12 ON asi11.AQTORStatsID = asi12.AQTORStatsID
    INNER JOIN tb_dAQTORStats astats on asi12.AQTORStatsID = astats.AQTORStatsID
WHERE 
    asi1.AQTORStatName = 'QtCPU_Average'
AND asi2.AQTORStatName = 'QtCPU_TopQuintile'
AND asi3.AQTORStatName = 'QtCPU_TopOnePercent'
AND asi4.AQTORStatName = 'QtCl_Average'
AND asi5.AQTORStatName = 'QtCl_TopQuintile'
AND asi6.AQTORStatName = 'QtCl_TopOnePercent'
AND asi7.AQTORStatName = 'UpdPrcStd_Average'
AND asi8.AQTORStatName = 'UpdPrcStd_TopQuintile'
AND asi9.AQTORStatName = 'UpdPrcStd_TopOnePercent'
AND asi10.AQTORStatName = 'RcRsUPr_Average'
AND asi11.AQTORStatName = 'RcRsUPr_TopQuintile'
AND asi12.AQTORStatName = 'RcRsUPr_TopOnePercent'

Ответы [ 4 ]

3 голосов
/ 04 июня 2009

ИМХО, этот вид кода (а также проблемы при разработке индексов) является частью цены, которую вы платите за гибкость идиомы «таблицы свойств» - вы платите свои деньги, и вы выбираете! -)

2 голосов
/ 04 июня 2009

Вот как вы это делаете:

SELECT 
  astats.AQTORStatsID
, astats.ServerName
, astats.Remarks
, astats.StatsBeginDateTime
, astats.StatsEndDateTime

, QtCPU_Average           = max(case when asi.AQTORStatName = 'QtCPU_Average'           then asi.AQTORStatValue end)
, QtCPU_TopQuintile       = max(case when asi.AQTORStatName = 'QtCPU_TopQuintile'       then asi.AQTORStatValue end)
, QtCPU_TopOnePercent     = max(case when asi.AQTORStatName = 'QtCPU_TopOnePercent'     then asi.AQTORStatValue end)
, QtCl_Average            = max(case when asi.AQTORStatName = 'QtCl_Average'            then asi.AQTORStatValue end)
, QtCl_TopQuintile        = max(case when asi.AQTORStatName = 'QtCl_TopQuintile'        then asi.AQTORStatValue end)
, QtCl_TopOnePercent      = max(case when asi.AQTORStatName = 'QtCl_TopOnePercent'      then asi.AQTORStatValue end)
, UpdPrcStd_Average       = max(case when asi.AQTORStatName = 'UpdPrcStd_Average'       then asi.AQTORStatValue end)
, UpdPrcStd_TopQuintile   = max(case when asi.AQTORStatName = 'UpdPrcStd_TopQuintile'   then asi.AQTORStatValue end)
, UpdPrcStd_TopOnePercent = max(case when asi.AQTORStatName = 'UpdPrcStd_TopOnePercent' then asi.AQTORStatValue end)
, RcRsUPr_Average         = max(case when asi.AQTORStatName = 'RcRsUPr_Average'         then asi.AQTORStatValue end)
, RcRsUPr_TopQuintile     = max(case when asi.AQTORStatName = 'RcRsUPr_TopQuintile'     then asi.AQTORStatValue end)
, RcRsUPr_TopOnePercent   = max(case when asi.AQTORStatName = 'RcRsUPr_TopOnePercent'   then asi.AQTORStatValue end)

from tb_dAQTORStats astats
join tb_rAQTORStatsItem asi on asi.AQTORStatsID = astats.AQTORStatsID  

group by 
  astats.AQTORStatsID
, astats.ServerName
, astats.Remarks
, astats.StatsBeginDateTime
, astats.StatsEndDateTime

Примечания:

  1. Хороший текстовый редактор с режимом столбцов или прямоугольным редактированием действительно помогает в таких вещах. UltraEdit или Emacs приходят на ум. Я создал выше в UltraEdit примерно за минуту.

  2. Ваш исходный запрос с ВНУТРЕННИМИ СОЕДИНЕНИЯМИ отбросил бы все чтения для данного сервера, если бы отсутствовал один тип чтения. Нехорошо. Этот запрос вернет по одной строке на сервер для любого сервера с хотя бы одним чтением. Если вы хотите вернуть все серверы, независимо от того, есть ли какие-либо показания, измените INNER JOIN на LEFT JOIN.

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

0 голосов
/ 04 июня 2009

Этот вид дизайна находится примерно на полпути от реляционного к чистому дизайну EAV (Entity-Attribute-Value). И да, у них есть некоторые отвратительные аспекты для базы данных SQL. Лучшее решение этой проблемы, которое я нашел, состоит в том, чтобы использовать кубы и / или сводные таблицы вместо того, чтобы пытаться вбить этот круглый стержень в квадратное отверстие реляционных представлений.

Вещи, которые вы можете использовать, которые подходят: SSAS, сводные отчеты служб Reporting Services, даже сводные таблицы Excel.

0 голосов
/ 04 июня 2009

Иметь таблицу, содержащую все возможные имена статистики (которые, я думаю, вы должны иметь в любом случае, с ограничением fkey из tb_rAQTORStatsItem на нее)

Тогда вы можете получить что-то вроде:

SELECT astats.QTORStatsID, astats.ServerName, astats.Remarks,
       astats.StatsBeginDateTime, astats.StatsEndDateTime,
       max(case item.AQTORStatName when 'QtCPU_Average' then AQTORStatValue end) as QtCPU_Average,
       max(case item.AQTORStatName when 'QtCPU_TopQuintile' then AQTORStatValue end) as QtCPU_TopQuintile,
       /* repeat for each statistic... */
FROM tb_dAQTORStats astats
     CROSS JOIN tb_rAQTORStatNames statnames
     LEFT JOIN tb_rAQTORStatsItem item
          ON item.AQTORStatName = statnames.AQTORStatName
             AND item.AQTORStatsID = astats.AQTORStatsID
GROUP BY astats.QTORStatsID, astats.ServerName, astats.Remarks,
         astats.StatsBeginDateTime, astats.StatsEndDateTime

Хотя это все еще довольно уродливо, по крайней мере, вы можете сократить N-way join до 3-way join. Да, это случай, когда гибкость и простота начинаются с разногласий. Добавление столбцов - это лучший способ решения проблемы, потому что схема базы данных будет точно соответствовать статистике, которую вы собираете, и типу ее: но вы должны поддерживать их синхронизацию.

(синтаксис запроса не проверен, я предполагаю, что CROSS JOIN работает так, как я ожидаю)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...