в чем различие между delete и delete
Отличия TRUNCATE от DELETE в языке T-SQL
Приветствую всех на сайте Info-Comp.ru! Сегодня я расскажу Вам об отличиях, которые существуют между инструкциями TRUNCATE TABLE и DELETE в языке T-SQL, Вы узнаете, в каких случаях лучше использовать DELETE, а в каких предпочтительней TRUNCATE.
Для того чтобы удалить данные из таблицы в Microsoft SQL Server можно использовать несколько инструкций, в частности DELETE и TRUNCATE TABLE. Эти операторы похожи, так как их предназначение одно – это удаление строк из таблицы. В связи с этим у многих возникают вопросы, например – а в чем отличие TRUNCATE от DELETE? или Когда лучше использовать TRUNCATE, а когда DELETE? Подобные вопросы задают и на собеседованиях, ведь понимание различий между этими операторами помогает разработчикам SQL эффективно работать с данными, строить приложения и запросы.
Заметка! Сборник статей для изучения языка T-SQL и Microsoft SQL Server – в этом материале я собрал лучшие свои статьи по SQL Server и сгруппировал их по уровню подготовки.
Для начала давайте дадим короткое определение этим двум операторам.
Что такое DELETE?
DELETE – это SQL инструкция языка T-SQL, которая удаляет одну или несколько строк из таблицы или представления в Microsoft SQL Server, при этом эта операция всегда полностью регистрируется в журнале транзакций, т.е. каждая удаленная строка.
Что такое TRUNCATE TABLE?
TRUNCATE TABLE – это SQL инструкция языка T-SQL, которая удаляет все строки в таблице, не записывая в журнал транзакций удаление отдельных строк данных. TRUNCATE TABLE похожа на инструкцию DELETE без предложения WHERE, но она выполняется быстрее и требует меньше ресурсов.
Сравнительная таблица отличий TRUNCATE TABLE и DELETE
Теперь давайте сформируем сравнительную таблицу, в которой отразим все отличия и особенности работы TRUNCATE TABLE и DELETE в языке T-SQL.
DELETE | TRUNCATE TABLE |
DELETE – это оператор DML (Data Manipulation Language) | TRUNCATE TABLE – это оператор DDL (Data Definition Language); |
DELETE может удалить часть данных за счет использования WHERE | TRUNCATE TABLE удаляет все данные из таблицы, секцию WHERE использовать нельзя |
DELETE записывает в журнал транзакций удаление каждой строки | TRUNCATE TABLE удаляет все строки в таблице, не записывая при этом удаление отдельных строк данных в журнал транзакций |
Для DELETE требуется больший объем журнала транзакций | Для TRUNCATE TABLE требуется меньший объем журнала транзакций, за счет того, что она не заносит в журнал запись для каждой удаляемой строки |
DELETE выполняется медленнее | TRUNCATE TABLE выполняется быстрее также за счет меньшего использования журнала транзакций |
DELETE удаляет строки по одной за раз | TRUNCATE TABLE удаляет все строки в таблице путем освобождения страниц |
DELETE создает блокировку на каждую строку, которую требуется удалить из таблицы | TRUNCATE TABLE блокирует в целом таблицу и страницу, чтобы удалить все записи |
DELETE сохраняет счетчик идентификаторов и не сбрасывает его до начального значения | TRUNCATE TABLE сбрасывает счетчик идентификаторов до начального значения |
DELETE может активировать триггер | TRUNCATE TABLE не может активировать триггер, поскольку в данном случае в журнал не записываются удаление отдельных строк |
DELETE сохраняет статистику объекта и выделенное пространство | TRUNCATE TABLE освобождает все страницы данных таблицы, поэтому TRUNCATE удаляет всю статистику и выделенное пространство |
DELETE можно использовать, если таблица является частью индексированного представления | TRUNCATE TABLE нельзя использовать, если таблица является частью индексированного представления |
Чтобы использовать DELETE, необходимы соответствующие права на удаление данных | Чтобы использовать TRUNCATE TABLE, у Вас должны быть права на ALTER TABLE, т.е. на изменение таблицы |
Таким образом, проанализировав таблицу, Вы можете решить, в каком случае для Вас будет лучше использовать TRUNCATE TABLE, а в каком DELETE.
Самым очевидным здесь является то, что если Вам нужно удалить не все данные из таблицы, а только часть, т.е. по условию WHERE, то Вы можете использовать только DELETE.
А, например, если Вам приходится периодически очищать всю таблицу, и значения идентификаторов не важны, то вполне возможно предпочтительней будет использовать TRUNCATE TABLE, так как это будет быстрей, и ресурсов затрачиваться будет меньше.
Пример отличия в работе TRUNCATE TABLE от DELETE
Для примера давайте создадим таблицу со столбцом идентификаторов, затем добавим в нее данные и удалим их сначала инструкцией DELETE, а потом попробуем выполнить то же самое только инструкцией TRUNCATE TABLE (предварительно пересоздав таблицу).
Создание тестовой таблицы
Выполняем удаление с помощью DELETE
Выполняем удаление инструкцией TRUNCATE TABLE
Как видите, в первом случае счетчик не сбросился, и нумерация продолжилась, а во втором счетчик начался с самого начала.
Заметка! Для комплексного изучения языка SQL и T-SQL рекомендую посмотреть мои видеокурсы по T-SQL, в которых используется последовательная методика обучения специально для начинающих.
Оператор delete (C++)
Отменяет выделение блока памяти.
Синтаксис
Комментарии
Аргумент Cast-Expression должен быть указателем на блок памяти, выделенный ранее для объекта, созданного с помощью оператора New. delete Оператор имеет результат типа void и поэтому не возвращает значение. Пример:
Использование delete в указателе на объект, не выделенный с помощью, new дает непредсказуемые результаты. Однако можно использовать delete для указателя со значением 0. Такая инициализация означает, что если new в случае сбоя возвращается значение 0, Удаление результата неудачной new операции является безвредным. Дополнительные сведения см. в разделе операторы new и DELETE.
new Операторы и delete можно также использовать для встроенных типов, включая массивы. Если pointer ссылается на массив, поместите пустые скобки ( [] ) перед pointer :
Использование delete оператора для объекта освобождает его память. Программа, которая разыменовывает указатель после удаления объекта, может создать непрогнозируемый результат или вызвать сбой.
Если delete используется для освобождения памяти для объекта класса C++, деструктор объекта вызывается до освобождения памяти объекта (если у объекта есть деструктор).
Если операнд delete оператора является изменяемым l-значением, его значение не определено после удаления объекта.
Использование оператора delete
Существует два синтаксических варианта для оператора delete: один для единичных объектов, а другой для массивов объектов. В следующем фрагменте кода показано, как они отличаются:
Следующие два варианта приводят к неопределенным результатам: использование формы массива delete ( delete [] ) для объекта и использование немассивного класса DELETE в массиве.
Пример
Принцип работы delete
Оператор delete вызывает оператор функции Delete.
Для объектов, не имеющих тип класса (класс, Структураили объединение), вызывается оператор глобального удаления. Для объектов типа класса имя функции освобождения разрешается в глобальной области, если выражение delete начинается с оператора унарного разрешения области ( :: ). В противном случае перед освобождением памяти оператор удаления вызывает деструктор объекта (если указатель не имеет значения null). Оператор удаления можно определять отдельно для каждого класса; если для некоторого класса такое определение отсутствует, вызывается глобальный оператор удаления. Если выражение удаления используется для освобождения объекта класса, статический тип которого имеет виртуальный деструктор, функция освобождение разрешается через виртуальный деструктор динамического типа объекта.
[C++] Всё ли мы знаем об операторах new и delete?
Привет! Ниже речь пойдет об известных всем операторах new и delete, точнее о том, о чем не пишут в книгах (по крайней мере в книгах для начинающих).
На написание данной статьи меня побудило часто встречаемое заблуждение по поводу new и delete, которое я постоянно вижу на форумах и даже(. ) в некоторых книгах.
Все ли мы знаем, что такое на самом деле new и delete? Или только думаем, что знаем?
Эта статья поможет вам разобраться с этим (ну, а те, кто знают, могут покритиковать:))
Note: ниже пойдет речь исключительно об операторе new, для других форм оператора new и для всех форм оператора delete все ниженаписанное также является правдой и применимо по аналогии.
Итак, начнем с того, что обычно пишут в книгах для начинающих, когда описывают new (текст взят «с потолка», но вцелом соответствует правде):
Оператор new выделяет память больше или равную требуемому размеру и, в отличие от функций языка С, вызывает конструктор(ы) для объекта(ов), под которые память выделена… вы можете перегрузить (где-то пишут реализовать) оператор new под свои нужды.
И для примера показывают примитивную перегрузку (реализацию) оператора new, прототип которого выглядит так
void* operator new (std::size_t size) throw (std::bad_alloc);
На что хочется обратить внимание:
1. Нигде не разделяют new key-word языка С++ и оператор new, везде о них говорят как об одной сущности.
2. Везде пишут, что new вызывает конструктор(ы) для объекта(ов).
И первое и второе является распространенным заблуждением.
Но не будем надеяться на книги для начинающих, обратимся к Стандарту, а именно к разделу 5.3.4 и к 18.6.1, в которых собственно и раскрывается (точнее приоткрывается) тема данной статьи.
5.3.4
The new-expression attempts to create an object of the type-id (8.1) or new-type-id to which it is applied. /*дальше нам не интересно*/
18.6.1
void* operator new(std::size_t size) throw(std::bad_alloc);
Effects: The allocation function called by a new-expression (5.3.4) to allocate size bytes of
storage suitably aligned to represent any object of that size /*дальше нам не интересно*/
Тут мы уже видим, что в первом случае new именуется как expression, а во втором он объявлен как operator. И это действительно 2 разные сущности!
Попробуем разобраться почему так, для этого нам понадобятся ассемблерные листинги, полученные после компиляции кода, использующего new. Ну, а теперь обо все по порядку.
new-expression — это оператор языка, такой же как if, while и т.д. (хотя if, while и т.д. все же именуются как statement, но отбросим лирику) Т.е. встречая его в листинге компилятор генерирует определенный код, соответствующий этому оператору. Так же new — это одно из key-words языка С++, что еще раз подтверждает его общность с if‘ами, for’ами и т.п. А operator new() в свою очередь — это просто одноименная функция языка С++, поведение которой можно переопределить. ВАЖНО — operator new() НЕ вызывает конструктор(ы) для объекта(ов), под который(ые) выделяется память. Он просто выделяет память нужного размера и все. Его отличие от сишных функций в том, что он может бросить исключение и его можно переопределить, а так же сделать оператором для отдельно взятого класса, тем самым переопределить его только для этого класса (остальное вспомните сами:)).
А вот new-expression как раз и вызывает конструктор(ы) объекта(ов). Хотя правильней сказать, что он тоже ничего не вызывает, просто, встречая его, компилятор генерирует код вызова конструктора(ов).
Для полноты картины рассмотрим следующий пример:
после исполнения данного кода, как и ожидалось, будет напечатано «Foo()». Разберемся почему, для этого понадобится заглянуть в ассемблер, который я немного прокомментировал для удобства.
(код получен компилятором cl, используемым в MSVS 2012, хотя в основном я использую gcc, но это к делу не относится)
Для тех, кто ничего не понял, вот (почти) аналог того, что получилось на сиподобном псевдокоде (т.е. не надо пробовать это компилировать :))
Приведенный код подтверждает все, написанное выше, а именно:
1. оператор (языка) new и operator new() — это НЕ одно и тоже.
2. operator new() НЕ вызывает конструктор(ы)
3. вызов конструктора(ов) генерирует компилятор, встречая в коде key-word «new»
Итог: надеюсь, эта статья помогла вам понять разницу между new-expressionи operator new() или даже узнать, что она (эта разница) вообще существует, если кто-то не знал.
P.S. оператор delete и operator delete() имеют аналогичное различие, поэтому в начале статьи я сказал, что не буду его описывать. Думаю, теперь вы поняли, почему его описание не имеет смысла и сможете самостоятельно проверить справедливость написанного выше для delete.
Update:
Хабражитель с ником khim в личной переписке предложил следующий код, который хорошо демонстрирует суть написанного выше.
delete, new[] в C++ и городские легенды об их сочетании
Если в коде на C++ был создан массив объектов с помощью «new[]», удалять этот массив нужно с помощью «delete[]» и ни в коем случае не с помощью «delete» (без скобок). Разумный вопрос: а не то что?
На этот вопрос можно получить широчайший спектр неразумных ответов. Например, «будет удален только первый объект, остальные утекут» или «будет вызван деструктор только первого объекта». Следующие за этим «объяснения» не выдерживают обычно никакой серьезной критики.
В соответствии со Стандартом C++, в этой ситуации поведение не определено. Все предположения – не более чем популярные городские легенды. Разберем подробно, почему.
Нам понадобится хитрый план с примером, который бы ставил в тупик сторонников городских легенд. Вот такой безобидный будет ок:
Здесь объект в массиве всего один. Если верить любой из двух легенд выше, «все будет хорошо» – утекать нечему и некуда, деструкторов будет вызвано ровно сколько нужно.
Идем на codepad.org, вставляем код в форму, получаем выдачу:
MEMORY WHAT. Что это было?
Здесь хотя бы с виду все хорошо. Что происходит? Почему так происходит? Почему поведение с виду разное?
Причина в том, что происходит внутри.
Когда в коде встречается «new Type[count]», программа обязана выделить память объема, достаточного для хранения указанного числа объектов. Для этого она использует функцию «operator new[]()». Эта функция выделяет память – обычно внутри просто вызов malloc() и проверка возвращаемого значения (при необходимости – вызов new_handler() и выброс исключения). Затем в выделенной памяти конструируются объекты – вызывается нужное число конструкторов. Результатом «new Type[count]» является адрес первого элемента массива.
Когда в коде встречается «delete[] pointer», программа должна разрушить все объекты в массиве, вызвав для них деструкторы. Для этого (и только для этого) ей нужно знать число элементов.
Важный момент: в конструкции «new Type[count]» число элементов было указано явно, а «delete[]» получает только адрес первого элемента.
Откуда программа узнает число элементов? Раз у нее есть только адрес первого элемента, она должна вычислить длину массива на основании одного этого адреса. Как это делается, зависит от реализации, обычно используется следующий способ.
При выполнении «new Type[count]» программа выделяет памяти столько, чтобы в нее поместились не только объекты, но и беззнаковое целое (обычно типа size_t), обозначающее число объектов. В начало выделенной области пишется это число, дальше размещаются объекты. Компилятор при компиляции «new Type[count]» вставляет в программу код, который реализует эти свистелки.
Итак, при выполнении «new Type[count]» программа выделяет чуть больше памяти, записывает число элементов в начало выделенного блока памяти, вызывает конструкторы и возвращает вызывающему коду адрес первого элемента. Адрес первого элемента будет отличаться от адреса, который возвратила функция выделения памяти «operator new[]()».
При выполнении «delete[]» программа берет адрес первого элемента, переданный в «delete[]», определяет адрес начала блока (вычитая ровно столько же, сколько было прибавлено при выполнении «new[]»), читает число элементов из начала блока, вызывает нужное число деструкторов, затем – вызывает функцию «operator delete[]()», передав ей адрес начала блока.
В обоих случаях вызывающий код работает не с тем адресом, который был возвращен функцией выделения памяти и позже – передан функции освобождения памяти.
Теперь вернемся к первому примеру. Когда выполняется «delete» (без скобок), вызывающий код понятия не имеет, что нужно проиграть последовательность со смещением адреса. Скорее всего, он вызывает деструктор единственного объекта, затем передает в функцию «operator delete()» адрес, который отличается от ранее возвращенного функцией «operator new[]()».
Что должно произойти? В этой реализации программа аварийно завершается. Поскольку Стандарт говорит, что поведение не определено, это допустимо.
Для сравнения, программа на Visual C++ 9 по умолчанию исходит сообщениями об ошибках в отладочной версии, но вроде бы нормально отрабатывает (по крайней мере, функция _heapchk() возвращает код _HEAP_OK, _CrtDumpMemoryLeaks() не выдает никаких сообщений). Это тоже допустимо.
Почему во втором примере поведение другое? Скорее всего, компилятор учел, что у типа char тривиальный деструктор, т.е. не нужно ничего делать для разрушения объектов, а достаточно просто освободить память, поэтому и число элементов хранить не нужно, а значит, можно сразу вернуть вызывающему коду тот же адрес, который вернула функция «operator new[]()». Никаких смещений адреса – точно так же, как и при вызове «new» (без скобок). Такое поведение компилятора полностью соответствует Стандарту.
Вы уже заметили, что выше по тексту встречаются функции выделения и освобождения памяти то с квадратными скобками, то без? Это не опечатки – это две разные пары функций, они могут быть реализованы совершенно по-разному. Даже когда компилятор пытается сэкономить, он всегда вызывает функцию «operator new[]()», когда видит в коде «new Type[count]», и всегда вызывает функцию «operator new()», когда видит в коде «new Type».
Обычно реализации функций «operator new()» и «operator new[]()» одинаковы (обе вызывают malloc()), но их можно заменить – определить свои, причем можно заменить как одну пару, так и обе, также можно заменять эти функции по отдельности для любого выбранного класса. Стандарт позволяет это делать сколько угодно (естественно, нужно адекватно заменить парную функцию освобождения памяти).
Это дает богатые возможности для неопределенного поведения. Если ваш код приводит к тому, что память освобождается «не той» функцией, это может приводить к любым последствиям, в частности, к повреждению кучи, порче памяти или немедленному аварийному завершению программы. В первом примере реализация функции «operator delete()» не смогла распорядиться переданным ей адресом и программа аварийно завершилась.
Самая приятная часть этого рассказа – вы никогда не сможете утверждать, что использование «delete» вместо «delete[]» (и наоборот – тоже) приводит к какому-то конкретному результату. Стандарт говорит, что поведение не определено. Даже полностью соответствующий Стандарту компилятор не обязан выдать вам программу с каким-либо адекватным поведением. Поведение программы, на которое вы будете ссылаться в комментариях и спорах, является только наблюдаемым – внутри может происходить все что угодно. Вы только констатируете наблюдаемое вами поведение.
Во втором примере с виду все хорошо… на этой реализации. На другой реализации функции «operator new()» и «operator new[]()» могут быть, например, реализованы на разных кучах (Windows позволяет создавать более одной кучи на процесс). Что произойдет при попытке возвратить блок «не в ту» кучу?
Кстати, рассчитывая на какое-то конкретное поведение в этой ситуации, вы автоматически получаете непереносимый код. Даже если на текущей реализации «все работает», при переходе на другой компилятор, при смене версии компилятора или даже при обновлении C++ runtime вы можете быть крайне неприятно удивлены.
Как быть? Смириться, не путать «delete» и «delete[]» и самое главное – не тратить зря время на «правдоподобные» объяснения того, что якобы произойдет, если вы их перепутаете. Пока вы будете спорить, другие разработчики будут делать что-то полезное, а для вас будет расти вероятность заслужить премию Дарвина.
Дмитрий Мещеряков
Департамент продуктов для разработчиков
В чем различие между delete и delete
Delete: To completely erase something.
Remove: To put away. (but it hasn’t been erased.)
Clear: To free or rid something of another thing.
Delete: To completely erase something.
Remove: To put away. (but it hasn’t been erased.)
Clear: To free or rid something of another thing.
They all mean the same thing but delete is more something you say where it relates to computers.
I should delete these old files.
Remove and clear are pretty similar. Feel free to use either
Символ показывает уровень знания интересующего вас языка и вашу подготовку. Выбирая ваш уровень знания языка, вы говорите пользователям как им нужно писать, чтобы вы могли их понять.
Мне трудно понимать даже короткие ответы на данном языке.
Могу задавать простые вопросы и понимаю простые ответы.
Могу формулировать все виды общих вопросов. Понимаю ответы средней длины и сложности.
Понимаю ответы любой длины и сложности.
Решайте свои проблемы проще в приложении!
( 30 698 )