Решил пойти другим путем и разбить запрос на 2 части. Вот такой простой запрос получился:
UPDATE dbo.Spending
SET SourceTransferIndex = tn.[Index] * 100000 + SourceTransferLocalIndex
FROM dbo.[Transaction] tn
WHERE tn.[Hash] = Spending.SourceTransactionHash
Индексы есть на tn.[Hash] и Spending.SourceTransactionHash (то есть объединяем индексированые поля, конечно, тип данных одинаковый).
Ну что может быть проще? Даже в простом хранилище ключ-значение очень просто выполнить такую операцию -- выберай порцию данных из dbo.Spending, находи по ключу [Hash] данные в dbo.[Transaction] и обновляй выбранные Spending. Что сложного? Делай порциями, диска вообще не требует.
И что вы думаете? MS SQL начала чего то мутить целый час, съела все место на диске и завершила работу с ошибкой нехватки места. Причем места отъела примерно столько же, сколько занимали обе таблицы. Ну дебилизм же
Здравствуйте, Shmj, Вы писали:
S>И что вы думаете? MS SQL начала чего то мутить целый час, съела все место на диске и завершила работу с ошибкой нехватки места. Причем места отъела примерно столько же, сколько занимали обе таблицы. Ну дебилизм же
Нормальное поведение. Данных очень много — это сколько? Размеры таблиц?
Ну и напоследок... Делай в не слишком длинных транзакциях. Порциями по десятку-другому тысяч записей. Потому как твой запрос, если он именно такой, как ты написал, стартует транзакцию и молотит данные. А закоммитит только после того, как обмолотит всё. Соответственно, при ошибке или если ты его остановишь, потянется rollback, который по времени будет ровно столько же длиться. И база будет пухнуть, потому что лог транзакций растет.
Здравствуйте, Shmj, Вы писали:
S>Ну что может быть проще? Даже в простом хранилище ключ-значение очень просто выполнить такую операцию -- выберай порцию данных из dbo.Spending, находи по ключу [Hash] данные в dbo.[Transaction] и обновляй выбранные Spending. Что сложного? Делай порциями, диска вообще не требует.
Если не поддерживать транзакции, то просто, конечно. А вот если тебе нужна возможность откатить все обратно при ошибке в середине процесса, то все несколько усложняется, не находишь?
Здравствуйте, fmiracle, Вы писали:
F>Если не поддерживать транзакции, то просто, конечно. А вот если тебе нужна возможность откатить все обратно при ошибке в середине процесса, то все несколько усложняется, не находишь?
А что делать если мне не нужна возможность откатить?
Здравствуйте, Shmj, Вы писали:
S>А что делать если мне не нужна возможность откатить?
Насколько я знаю, в постгресе есть возможность пометить таблицы, как не участвующие в логах транзакций. Наверняка подобное безобразие имеется и в MSSQL.
Давай немного перепишем, чтобы более наглядно было:
update s
set SourceTransferIndex = tn.[Index] * 100000 + SourceTransferLocalIndex
from dbo.Spending s
join dbo.[Transaction] tn on tn.[Hash] = s.SourceTransactionHash
S>Индексы есть на tn.[Hash] и Spending.SourceTransactionHash (то есть объединяем индексированые поля, конечно, тип данных одинаковый).
И вот тут как раз пригодился бы план запроса, чтобы посмотреть, что же движок собирается сделать.
И очень пригодились бы скрипты создания таблиц, участвующих в запросе, вместе со всеми индексами.
Есть подозрение, что план можно существенно улучшить.
S>Ну что может быть проще?
Проще всего обвинить шуруповерт в том, что он плохо забивает гвозди, не разобравшись толком.
В целом твои запросы вызывают очень много вопросов по дизайну БД, BTW.
S>Даже в простом хранилище ключ-значение очень просто выполнить такую операцию -- выберай порцию данных из dbo.Spending, находи по ключу [Hash] данные в dbo.[Transaction] и обновляй выбранные Spending. Что сложного? Делай порциями, диска вообще не требует.
1. Про поддержку транзакций не забывай. Она требует диска в любом случае.
2. Ты можешь обновлять данные порциями и в T-SQL, объявив это явно. Вполне себе годная стратегия, которая применяется в некоторых сценариях
массового обновления данных.
S>И что вы думаете? MS SQL начала чего то мутить целый час, съела все место на диске и завершила работу с ошибкой нехватки места. Причем места отъела примерно столько же, сколько занимали обе таблицы. Ну дебилизм же
Нет. Не дебилизм. Кто-то просто не умеет готовить РСУБД, не понимая их основные принципы.
Здравствуйте, Sinix, Вы писали:
_AB>>В целом твои запросы вызывают очень много вопросов по дизайну БД, BTW. S>Эмм, а только меня смущает джойн по хэшам?
Здравствуйте, Shmj, Вы писали:
S>А что именно смущает?
Там точно хэши, вы не шутите?
Если коротко — то 99% за то, что у вас есть серьёзные архитектурные просчёты. Только навскидку:
* Коллизии
* Высокая стоимость джойнов
* Необходимость обновлять хэши при изменении любого поля, по которому считается хэш.
* Необходимость следить за совпадением реализаций на всех платформах, на которых считается хэш (нетривиальное дело, особенно если возможны несколько представлений строк и никто не следит за unicode normalization)
Здравствуйте, Sinix, Вы писали:
S>Если коротко — то 99% за то, что у вас есть серьёзные архитектурные просчёты. Только навскидку: S>* Коллизии S>* Высокая стоимость джойнов S>* Необходимость обновлять хэши при изменении любого поля, по которому считается хэш. S>* Необходимость следить за совпадением реализаций на всех платформах, на которых считается хэш (нетривиальное дело, особенно если возможны несколько представлений строк и никто не следит за unicode normalization)
Все мимо. Хеши являются основой системы (см. блокчейн), они не изменяются, на всех платформах одинаковы. Коллизий нет, там 32 байта.
Здравствуйте, Shmj, Вы писали:
S>Все мимо. Хеши являются основой системы (см. блокчейн), они не изменяются, на всех платформах одинаковы. Коллизий нет, там 32 байта.
Таки не мимо. У вас по определению получается рандомное распределение значений, что вместе с большим размером ключа (и любого вторичного индекса, если хэш включён в clustered-индекс) даёт кучу logical reads. Серьёзно, у вас получается где-то 100-200 строк индекса на страницу против 400-700 для long-а (прикинул на пальцах, уверен только в порядке цифр). Если у заказчика не ssd — вы ещё и в iops уткнётесь. Это раз.
У вас с какого-то перепуга идёт массовое обновление данных, хотя блокчейн построен на идее immutable-блоков — это два.
Ну и СУБД по определению не самый лучший способ для организации блокчейн-хранилищ, особенно если нужно low-latency distributed storage типа такого — три.
Если штука по ссылке не нужна — чего вы вообще хотите добиться с помощью хэшей?
Здравствуйте, Слава, Вы писали:
С>Здравствуйте, Shmj, Вы писали:
S>>А что делать если мне не нужна возможность откатить?
С>Насколько я знаю, в постгресе есть возможность пометить таблицы, как не участвующие в логах транзакций. Наверняка подобное безобразие имеется и в MSSQL.
В реальности это мало что даёт. На чтение и так никаких логов не пишется, а вот при любом изменении данных (в т. ч. обновления) постгрес создаёт новые записи (в т. ч. и в нелоггируемых таблицах) и основная проблема (при интенсивных изменениях) как эти старые записи пометить устаревшими (вакуум), а потом ещё и переиспользовать место под ними. Там куча тонкостей.
Если не нужны транзакции, то значит не нужно использовать реляционные СУБД с ACID. Есть куча более подходящих систем: какой-нибудь NoSQL, ElasticSearch/SOLR, а то может и быть и обычный файлик
Раз транзакции тебе не нужны — обновляй по частям.
Если не получиться — пиши в личку
while 1=1
begin
UPDATEtop(50000) dbo.Spending
SET SourceTransferIndex = tn.[Index] * 100000 + SourceTransferLocalIndex
FROM dbo.[Transaction] tn
WHERE tn.[Hash] = Spending.SourceTransactionHash
and SourceTransferIndex <> tn.[Index] * 100000 + SourceTransferLocalIndexif @@rowcount =0
break;
end
Здравствуйте, Shmj, Вы писали:
S>И что вы думаете? MS SQL начала чего то мутить целый час, съела все место на диске и завершила работу с ошибкой нехватки места.
Пока SQL не объяснить во всех подробностях что ты хочешь (это талмуды общеизвестного, а далее недокументированные талмуды), время выполнения и вообще выполнение от погоды на Марсе зависят. Причем то что вчера работало быстро завтра может в 100 раз медленнее заработать. SQL — это анти реал тайм приложения, где не существует понятия сложности и времени.