Pull to refresh

Comments 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` если быть точным.
UFO just landed and posted this here

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

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

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

И очень зря.

Та же SSMS использует под капотом именно его, а главное — это самый низкоуровневный и эффективный способ
UFO just landed and posted this here
Кому как. Мне, например, быстрее и проще написать bcp с параметрами, чем тыкать «мышей» по чекбоксам.
UFO just landed and posted this here
Мне тоже показалось, что игнорировать 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"));

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

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

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


Можно было бы сразу и ссылку прикрепить?
Sign up to leave a comment.

Articles