Создание секционированного представления подробных таблиц, когда CHECK находится в таблицах заголовка - PullRequest
1 голос
/ 23 мая 2011

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

Я настроил представления, которые следуют формату «SELECT + UNION ALL». Я также установил контрольные ограничения на таблицы заголовков, чтобы ограничить их значения соответствующим годом. Это позволяет оптимизатору запросов сервера SQL запрашивать только определенные таблицы при выполнении запроса, ограниченного предложением WHERE. Потрясающие. До этого момента эту информацию можно найти где угодно и где угодно, выполнив поиск разделенных представлений.

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

Единственное решение, о котором я подумал, - это добавить столбец 'year' в подробные таблицы, а затем добавить еще один подпункт where к запросам. Есть ли что-нибудь, что я могу сделать, чтобы создать секционированное представление таблиц подробностей, используя существующее ограничение внешнего ключа?


Вот некоторые DDL для справки:

CREATE TABLE header2008 (
    hid INT PRIMARY KEY,
    dt DATE CHECK ('2008-01-01' <= dt AND dt < '2009-01-01')
)

CREATE TABLE header2009 (
    hid INT PRIMARY KEY,
    dt DATE CHECK ('2009-01-01' <= dt AND dt < '2010-01-01')
)

CREATE TABLE detail2008 (
    did INT PRIMARY KEY,
    hid INT FOREIGN KEY REFERENCES header2008(hid),
    value INT
)

CREATE TABLE detail2009 (
    did INT PRIMARY KEY,
    hid INT FOREIGN KEY REFERENCES header2009(hid),
    value INT
)

GO
CREATE VIEW headerAll AS
SELECT * FROM header2008 UNION ALL
SELECT * FROM header2009
GO

CREATE VIEW detailAll AS
SELECT * FROM detail2008 UNION ALL
SELECT * FROM detail2009
GO

--This only hits the header2008 table (GOOD)
SELECT * 
FROM headerAll h
WHERE dt = '2008-04-04'

--This hits the header2008, detail2008, and detail 2009 tables. (BAD)
SELECT * 
FROM headerAll h
INNER JOIN detailAll d ON h.hid = d.hid
WHERE dt = '2008-04-04'

1 Ответ

0 голосов
/ 03 июля 2011

Поскольку вы не собираетесь использовать многораздельные таблицы, я предполагаю, что вы не можете ориентироваться на 2005+ Enterprise Edition или более позднюю версию.

Вот альтернатива добавлению нового физического столбца в ваши таблицы:

CREATE VIEW detailAll AS
    SELECT 2008 AS Year, * FROM detail2008
    UNION ALL
    SELECT 2009, * FROM detail2009

затем,

SELECT * 
    FROM headerAll h
    INNER JOIN detailAll d ON h.hid = d.hid
    WHERE dt = '2008-04-04' AND d.Year = 2008

Прежде чем вы убежите и реализуете это, есть ловушка;ну, на самом деле, две зацепки.

Это решение, как и представление headerAll в том виде, как оно написано, не может вместить параметры в столбце разделения и все же выполняет удаление раздела.Использование предиката поиска WHERE dt = @date AND d.Year = YEAR(@date) вызывает сканирование таблиц по всем таблицам в обоих представлениях, поскольку оптимизатор запросов предполагает, что @date является произвольным значением (и это невозможно исправить).Это рецепт для снижения производительности, если представление открыто публикуется в API вашей базы данных: нет ограничений на параметризацию в запросах, и большинство авторов запросов и ORM склонны использовать параметризованные запросы везде, где это возможно (это почти всегда хорошо!).

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

Обратите также внимание, что использование динамического выполнения строк позволит вам писать запросы непосредственно к базовым таблицам вместо введенияUNION редактируемое представление для каждой «таблицы».Я не думаю, что с последним что-то не так, но это вариант, который вы, возможно, не рассматривали.

...