Обновить

Комментарии 31

А пробовали добавить столбец с индексом и именем вроде copied (default = 0),
постепенно копировать строки пачками по n штук как-то так:
SELECT TOP n * FROM… WHERE copied = 0
и потом отмечать в скопированных строках copied = 1?
а третий способ разве не оно? Только вместо добавления столбца разбиваем уже имеющийся ключ на интервалы.
а третий способ разве не оно?
Как я понял — там «маркером» того, что строки перенесены было их удаление из исходной таблицы после копирования. Удаление строки это намного более затратная операция по сравнению с изменением одного поля поля в строке. Учитывая, что сервер живой и там еще какие-то страсти с транзакциями-логированием удаленных строк — мне кажется мой вариант будет быстрее и не такой чувствительный для вебсервиса.
Можно не удалять, если ключ идет последовательно от 1 до 100500, то мы просто копируем записи с ключом от i*1000 до (i+1)*1000-1, запоминая на каком i мы в прошлый раз остановились. А в конце, когда все записи скопированы — truncate (или как оно в mssql называется) чтобы быстро очистить место.
Как насчет BULK INSERT?
Она вроде как даже в лог не пишет, тоже плюс. Выгружать порциями, как в способе 3.

А еще можно попробовать настроить репликацию…
Вы угадали мои мысли в MySQL есть например: LOAD DATA INFILE `filePath` INTO TABLE `tableName` выполняется кратно быстрее, как сравнивать O(n^2) с O(n), но заметил, что автор упомянул пункт 2) SELECT INTO OUTFILE `filePath` если быть точным.
НЛО прилетело и опубликовало эту надпись здесь

+1 за мастер экспорта импорта. Но он использует не bulk insert, а её другой аналог доступный только в .NET — прямая запись данных в таблицу, без всяких insert. Что-то вроде прямой передачи данных в бинарном формате. Однако, замечено на практике, что если ставить галочку на DELETE DATA BEFORE TRANSFER, и у вас осталось мало места а transaction log, то процесс все таки застревает. Возможно, для удаления он всё же используют transaction log.

НЛО прилетело и опубликовало эту надпись здесь
Очень хочется знать, как работает эта «прямая запись в таблицу» :) Можем поговорить на двоичном уровне, уровне байт, блоков?)
Если есть кластерный индекс, любая запись должна пройти через движок БД, что бы попасть туда, куда ей нужно. А без кластерного индекса, потом будет реиндексация. Никакой «прямой записи» в принципе быть не может. Скорее всего, там оптимизация в момент записи. Просто монопольный захват таблиц или что-то в этом роде.
Я не увидел во всех способах обоснования. Да были попытки, но как сказал Сергей: Владимир не заморачивайся! При необходимости мы расширим кластер и все будет работать.

interfax.ru ©
Мне кажется не упомянут самый надёжный способ: bcp.exe

И очень зря.

Та же SSMS использует под капотом именно его, а главное — это самый низкоуровневный и эффективный способ
НЛО прилетело и опубликовало эту надпись здесь
Кому как. Мне, например, быстрее и проще написать bcp с параметрами, чем тыкать «мышей» по чекбоксам.
НЛО прилетело и опубликовало эту надпись здесь
Мне тоже показалось, что игнорировать BCP в такой задаче довольно странно.
Я как-то переносил достаточно большие таблицы. Таблички в несколько миллионов строк копируются за пару минут.

Ещё как писали в похожей статье по postgre, хороший способ:
1) переименовываем существующую таблицу в что-нибудь, например дописываем окончание _old
2) Создаём новую пустую таблицу с точно такой же структурой. Структуру взять не сложно, главное не забудьте про индексы. Сделать 1 и 2 запрос можно одним запросом, поэтому ни один скрипт не прервется, и просто запишет данные а новую таблицу. Простоя не будет.
3) имея неменяющуюся таблицу _old, можно начать её медленно переносить. Если планируете порционно, то вообще стоит удалить индексы (кроме главного ключевого ), потому-что удаляя после запроса по 100 000 записей, будут также перестраиваться все индексы, это дорогая операция для такой толстой таблицы. Ну а я все же рекомендую переносить через мастер экспорта импорта, он не будет перестраивать индексы пока все не перенесет .

Тоже отличный вариант. Делали так на MySQL, когда нужно было 300гиговую таблицу перенести.
Если, пока, я не заморачиваюсь над сбоями, с помощью linq2db я это дело делаю так:

using (var source = CreateSourceConnection())
using (var destination = CreateDestinationConnection())
{
    // extract and transform, lazy
    var sourceQuery = source.GetTable<SomeTable>()
        .Select(s => new SomeDestTable{...});

    // load data by 1000 records, configurable
    destination.GetTable<SomeDestTable>().TableName("SomeNewName")
       .BulkCopy(sourceQuery);
}


Данные влетают в базу со скоростью мысли, при чем это могут быть любые сервера и я одновременно могу делать Transform. Такой себе ETL через ORM.

Если же у вас базы на том же сервере. То почему же не сделать это одним запросом.

using (var source = CreateSourceConnection())
{
    // extract and transform, lazy
    var sourceQuery = source.GetTable<SomeTable>()
        .Select(s => new SomeDestTable{...});
  
   // appropriate INSERT INTO will be genarated
   sourceQuery.Insert(source.GetTable<SomeDestTable>()
        .DatabaseName("OtherDb").TableName("SomeNewName"));

}
Вы забыли запрос, который отключает индексы на таблице назначения. Добавьте его скорее.
Это проблема, запустить дополнительньный тюнингующий запрос? Тем более что оно варьируется от базы к базе.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Иногда бывает что DBA и Developer это один и тот же человек. Особенно в маленьких компаниях.
НЛО прилетело и опубликовало эту надпись здесь
Это не размер для баз сейчас, так базочка. Совсем не то когда окупается DBA. По крайней мере у нас так.
НЛО прилетело и опубликовало эту надпись здесь
Мы про DevOps говорим или о DBA? Хотя я уже и разницы сильно не ощущаю.
Да, проблемы негров белых не волнуют. До тех пор, пока это не оказывается база несколько терабайт SQL для 1С, в которой торчат онлайн 2-3 тыщ пользователей в терминале по всей России)

Для чего давать советы по решению задачи, которые сам не пробовал?
Где-то слышал/читал/увидел, сам не попробовал, но расскажу, статью напишу побольше, тема важная.

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


Можно было бы сразу и ссылку прикрепить?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации