#sql-server #tsql #common-table-expression
#sql-server #tsql #common-table-expression
Вопрос:
Платформа БД — MS SQL Server 2008R2 У меня есть эта таблица —
CREATE TABLE [dbo].[CaseTest](
[SampleText] [varchar](5) NULL,
[ID] [int] NULL,
[Name] [nchar](10) NULL
)
GO
Заполняется образцами данных
INSERT INTO CaseTest
VALUES ('Text1',1,NULL),
('Text2',2,NULL),
('Text3',3,NULL),
('Text4',4,NULL),
('Text5',5,NULL)
Теперь, когда я запускаю следующий запрос, я действительно не ожидал никаких изменений в данных, но я обнаружил, что фактические данные таблицы были обновлены.
WITH CTE AS(
SELECT * FROM casetest
)
UPDATE CTE SET Name = 'NameText'
Это ожидаемое поведение? Как это происходит на самом деле?
Комментарии:
1. Учитывая, что CTE существует только для одного оператора, который следует за ним, и поэтому
UPDATE
это был единственный оператор, который мог «видеть» этот конкретный CTE, чего вы ожидалиUPDATE
, что он будет делать каким-либо значимым образом, если это не повлияет на базовую таблицу?2. Верно. Однако, поскольку CTE — это просто объект в памяти, я действительно не ожидал, что он выполнит фактическое обновление. Я предположил, что это будет бессмысленно, поскольку CTE будет обновлен и больше не будет доступен. Думаю, я предположил неправильно 🙂
3. CTE не является «объектом в памяти» — это именованный запрос, который может быть включен в более крупный запрос — ничего не материализуется (ни в памяти, ни на диске), и он также не оптимизируется отдельно.
4. Это ожидаемое поведение и очень полезно, когда вы хотите использовать оконные функции в
delete
update
операторе or, например, для удаления дубликатов или заполнения последовательных номеров.
Ответ №1:
Как вы сами заметили в комментарии:
Я предположил, что это было бы бессмысленно
И, действительно, это было бы для любого из операторов, которые фактически вносят изменения в базу данных — каждая такая операция может быть оптимизирована как неоперативная. И поэтому в таком случае на самом деле не имело бы смысла даже разрешать вам писать что-то другое, кроме a SELECT
, после создания CTE.
Но это не тот маршрут, который они выбрали для перехода — они позволяют UPDATE
записывать , INSERT
, DELETE
, и т. Д. По той же логике, по которой они позволяют применять определенные операции обновления к представлениям. При условии, что компонент database engine может принять ваше UPDATE
заявление и через CTE может определить единственную целевую таблицу UPDATE
, UPDATE
доступ к которой будет разрешен через CTE.
поскольку CTE — это просто объект в памяти
Это не так. Это просто именованный запрос, при записи CTE ничего не выполняется. По сути, CTE вставляется в конечный запрос, который его использует (во всех местах, где на него ссылаются), а затем весь запрос оптимизируется и выполняется.
Компонент database engine может решить, в момент оптимизации конечного запроса, материализовать часть или все CTE в хранилище (с помощью своих операторов спула), но это решение об оптимизации, которое принимается позже, и которое механизм в равной степени может решить использовать даже для простых, неЗапросы CTE.