У меня есть служба Go в качестве задания cron для проверки всех данных из таблицы базы данных раз в неделю. Логика очень проста: сервис Go извлекает все строки из исходной таблицы и выполняет некоторую логику с данными. Однако есть некоторая проблема: у меня есть 3.371.351 или ~3 миллиона строк и 400 столбцов из исходной таблицы, а я получаю только около 138.912 или ~100 тысяч строк (хранящихся в срезе Go), что указывает на то, что несколько строк не были получены полностью. по запросу, даже если процесс запроса успешно выполнен.
Вот мой код Go, который выполняет простой оператор SELECT
:
func (repository Repository) GetAllData() ([]entity.ExampleStruct, error) {
sql := fmt.Sprintf("SELECT * FROM [%s].[schema_data].[%s]", viper.GetString("SQL_SERVER_DBNAME"), viper.GetString("SQL_SERVER_TABLE"))
rows, err := repository.sqlServerConnection.Query(sql)
if err != nil {
return nil, err
}
defer rows.Close()
if rows.Err() != nil {
return nil, rows.Err()
}
var exampleStructList []entity.ExampleStructList
for rows.Next() {
var exampleStruct entity.ExampleStruct
err := rows.Scan(// scan struct here)
if err != nil {
return nil, err
}
exampleStructList = append(exampleStructList , exampleStruct)
}
return exampleStructList, nil
}
Раньше я сравнивал запрос с предложением WITH (NOLOCK)
, чтобы ускорить выполнение оператора SELECT
, и без него, но, похоже, результаты остались такими же.
Что интересно, я могу получить правильное количество строк, используя запрос COUNT(*)
.
Я также получил информацию от моего администратора базы данных о том, что у них есть несколько операций восстановления в базе данных и таблице для обновления данных. Я предполагаю, что операция восстановления может повлиять на мой процесс выборки строк.
Иногда у меня возникала ошибка при получении данных, как показано ниже:
"Error": {
"Number": 927,
"State": 6,
"Class": 14,
"Message": "Database 'xx' cannot be opened. It is in the middle of a restore.",
"ServerName": "xx",
"ProcName": "",
"LineNo": 1,
"All": [
{
"Number": 927,
"State": 6,
"Class": 14,
"Message": "Database 'xx' cannot be opened. It is in the middle of a restore.",
"ServerName": "xx",
"ProcName": "",
"LineNo": 1,
"All": null
}
]
}
Мой ожидаемый результат: оператор SELECT
должен возвращать полную запись с тем же количеством строк, что и исходная таблица.
Например, если исходная таблица имеет 3 миллиона строк, я также должен получить ровно 3 миллиона строк из моего оператора SELECT *
.
Записывает ли сервис какие-либо данные (обратно в ту же базу данных или куда-либо еще) или просто читает и проверяет? Если последнее, можете ли вы просто выполнить чтение и проверку в SQL (например, в хранимой процедуре)? 3 миллиона строк * 400 столбцов — это много данных, как насчет их пакетной обработки? Вам действительно нужны все 400 столбцов?
@allmhuran мой сервис просто читает и проверяет все данные, ничего особенного. Можете ли вы дать мне представление о процессе пакетной обработки? это в коде Go? или на уровне SQL-запроса с использованием LIMIT? И да, мне нужны все колонки для нужд бизнеса
@DaleK Я пытался его не использовать, но результат тот же.
Я не имел в виду, что nolock
имеет отношение к этой проблеме... просто к вашему сведению... не используйте его.
@DaleK Понятно, я возьму это на заметку. Итак, должно ли быть действие восстановления разрушает строки?
То, как именно вам следует выполнять пакетную обработку, будет зависеть от вашей схемы. Общий шаблон таков: «используйте столбец (или несколько столбцов, если необходимо) для фильтрации и отслеживайте, что вы делаете». Используемые вами столбцы должны быть проиндексированы и уникальны. Если ваш кластерный индекс находится в чем-то вроде столбца identity
, это прекрасно работает. На SO уже есть различные вопросы, посвященные этому, например здесь и здесь.
Вам следует переместить проверку rows.Err()
после цикла for rows.Next() {
(вероятно, вы пропустили ошибку; ошибки могут возникнуть при получении результатов). См. документацию по базе данных/sql и этот пример.
Это очень много данных, которые нужно сохранить в памяти. У меня такое ощущение, что сервис Go не подходит для решения этой задачи. Нельзя ли делать манипуляции с базой данных как процедуру, а потом позволить сервису ее вызвать?
@allmhuran, хорошо, спасибо за ссылку, кажется, просто реализуем подход к нумерации страниц, если я не ошибаюсь.
@Brits, я попробую переместить rows.Err()
и посмотреть, что получится, спасибо
@siggemannen, к сожалению, у меня нет доступа к базе данных, потому что она принадлежит другой команде
И ты не можешь поговорить с этой командой? Какую логику вы вообще используете в своем сервисе? Вам нужно постоянно отслеживать все строки? Что произойдет, если вы просто «намотаете» строки, не сохраняя их, извлекается ли все или тоже забивается?
@siggemannen Привет, я хочу сообщить вам новости: я связался с командой администраторов баз данных, чтобы они могли настроить время восстановления, и это действительно сработало. Я могу получить полную запись.
@mathiasyeremia рада это слышать! совместная работа - хороший способ решить проблемы :)
Решено: причина в активности восстановления, поэтому мне нужно получить данные, когда расписание восстановления отключено.
Вам следует прочитать и понять все последствия использования
nolock
, потому что вы когда-либо его использовали. Вряд ли это будет то, что вы думаете.