#c# #.net #performance #file #csv
#c# #.net #Производительность #файл #csv
Вопрос:
У меня есть CSV-файл. Каждая строка состоит из одного и того же формата, например/
I,h,q,q,3,A,5,Q,3,[,5,Q,8,c,3,N,3,E,4,F,4,g,4,I,V,9000,0000001-100,G9999999990001800000000000001,G9999999990000001100PDNELKKMMCNELRQNWJ010, , , , , , ,D,Z,
У меня есть Dictionary<string, List<char>>
Он заполняется путем открытия файла, чтения каждой строки, извлечения элементов из строки и добавления их в словарь, затем файл закрывается.
Словарь используется в другом месте программы, где он принимает входные данные в программу, а затем находит ключ в словаре и использует 24 элемента для сравнения с входными данными.
StreamReader s = File.OpenText(file);
string lineData = null;
while ((lineData = s.ReadLine()) != null)
{
var elements = lineData.Split(',');
//Do stuff with elements
var compareElements = elements.Take(24).Select(x => x[0]);
FileData.Add(elements[27], new List<char>(compareElements));
}
s.Close();
Мне только что сказали, что размер CSV-файла теперь будет 800 мб и в нем будет примерно 8 миллионов записей. Я только что попытался загрузить это на свой двухъядерный 32-разрядный ноутбук Win с 4 ГБ оперативной памяти в режиме отладки, и он выдал OutOfMemoryException
.
Теперь я думаю, что лучшим вариантом будет не загружать файл в память, но мне нужно найти способ быстрого поиска в файле, чтобы увидеть, есть ли во входных данных соответствующий элемент, равный element[27]
, а затем взять первые 24 элемента в этом CSV и сравнить его с входными данными.
a) Даже если бы я придерживался этого подхода и использовал 16 ГБ оперативной памяти и 64-разрядную версию Windows, было бы нормально иметь такое количество элементов в словаре?
б) Не могли бы вы предоставить какой-нибудь код / ссылки на способы быстрого поиска в CSV-файле, если вы не считаете использование словаря хорошим планом
ОБНОВЛЕНИЕ: Хотя я принял ответ, мне просто интересно, что думают люди об использовании FileStream для выполнения поиска, а затем извлечения данных.
Комментарии:
1. Не ответ, просто предложение: используйте для этого базу данных, а не CSV-файл!! Если вам нужен один файл базы данных, SQLite — это то, что вам нужно.
2. сохранение данных объемом 1 ГБ в памяти определенно не самый разумный выбор. Вероятно, вы не хотите, чтобы программа занимала всю вашу свободную оперативную память. вместо этого используйте СУБД.
3. @Marco Вы хотите сказать, что созданный файл базы данных — это один файл? Если это так, я предполагаю, что могу импортировать CSV-файл в БД, создав новый файл БД и удалив все старые?
4. Вы могли бы использовать это средство чтения CSV: codeproject.com/KB/database/CsvReader.aspx
5. Да. SQLite (как и любая база данных) организован в виде таблиц, а они — в виде столбцов (очень простое и краткое описание). Итак, вы должны спроектировать свою базу данных, а затем, используя поток, импортировать каждую строку CSV в вашу базу данных. Наконец, вы должны преобразовать свое приложение, чтобы оно могло использовать базу данных, а не CSV. SQLite хорош тем, что для него не требуется устанавливать сервер, но вы можете использовать его везде во время выполнения; более того, это один файл и без лицензии.
Ответ №1:
Если вы планируете выполнять поиск в таком количестве записей, я бы предложил массово вставлять файл в СУБД, такую как SQL Server, с соответствующими индексами для полей, которые будут вашими критериями, а затем использовать SQL-запрос для проверки существования записи.
Комментарии:
1. Обычно я бы согласился, но эта программа предназначена для клиента, не обладающего знаниями в области ИТ, и мне кажется, что для импорта такого количества данных в базу данных потребуется управление
2. Затем попробуйте использовать простую СУБД, такую как MS Access. Даже это может очень помочь.
3. Но система должна сама загрузить его в DMBS … в качестве первой части чтения файла. Проблема, вероятно, заключалась бы в создании структуры, которая была бы оптимальной. Если бы вы могли использовать какую-нибудь небольшую базу данных lightwieght, такую как SQLite, это, вероятно, было бы проще всего
4. @Jon: Не могли бы вы создать для них веб-приложение? Кто отвечает за данные?
5. Я с этим не работал, но вам, вероятно, также могло бы сойти с рук использование SQL Server CE, и учитывая, с чем вы работаете. Net, это могло бы лучше вписаться в вашу упаковку и т.д.
Ответ №2:
У нас была аналогичная проблема с импортом большого CSV-файла, содержащего данные, которые необходимо было объединить. В конце мы выполнили массовую вставку в таблицу SQL Server и использовали SQL для выполнения агрегации. В итоге это было довольно быстро (пара минут от начала до конца).
Комментарии:
1. Упс, только что понял, что я продублировал ответ Иоанниса… Тогда, должно быть, это хорошая идея.
Ответ №3:
Вам доступно несколько вариантов, но да, я бы согласился, что загрузка этих данных в память — не лучший вариант.
a) Вы могли бы загрузить данные в реляционную базу данных, хотя это может быть излишним для такого типа данных.
б) Вы могли бы использовать решение NoSQL, такое как RavenDB. Я думаю, это может быть хорошим вариантом для вас.
c) Вы могли бы использовать более эффективный вариант физического хранилища, такой как Lucene
d) Вы могли бы использовать более эффективный вариант кэширования в памяти, такой как Redis.
Ответ №4:
Решением может быть разбиение файла на несколько файлов меньшего размера и параллельный поиск в каждом файле. Порядок поиска будет меньше или равен n (чтение всего файла)
Комментарии:
1. Не могли бы вы продемонстрировать пример?
2. Хорошо, если у вас есть файл с данными объемом 1 ГБ, разделите его на 10 файлов по 100 мг, а затем при запуске пользовательских запросов создайте поток 10, который выполняет команду поиска в каждом файле с максимальной точностью, вы можете остановить весь поиск и остановить его
3. Ага, значение, которое вы ищете, уникально или нет? и как вы создаете файл?
4. Значение должно быть уникальным. Я не создаю CSV-файл, который делает клиент
Ответ №5:
Поскольку остальная часть вашей программы использует записи StringDictionary, вам все равно в идеале необходимо сохранять ваши результаты в памяти — на самом деле вы не хотите запрашивать базу данных 1000 раз. (Это может зависеть от того, находится ли ваша программа на сервере БД)!
Я бы изучил использование памяти StringDictionary для вашей структуры и посмотрел, каковы ваши теоретические максимумы, и посмотрим, сможете ли вы учесть это с оговоркой о функциональных требованиях. В противном случае поищите более эффективный способ хранения — например, потоковая передача ваших результатов в XML-файл будет быстрее, чем доступ к базе данных.
Комментарии:
1. Не совсем понимаю ваш ответ, но если я нахожу соответствие между файлом / словарем и входными данными, я пишу уникальный идентификатор, передаю / завершаю строку в новый файл
2. вы указали «Словарь используется в другом месте программы», поэтому я предполагаю, что именно поэтому вы хотите сохранить его в памяти? Если к этому промежуточному словарю часто обращаются, вы бы не хотели, чтобы эти обращения осуществлялись по потенциально медленной ссылке на базу данных.
Ответ №6:
- забудьте о MS access. Действительно.
- попробуйте sqlite, его будет более чем достаточно для нескольких миллионов строк
- если вы не можете проиндексировать свои данные, то не используйте базу данных, используйте внешнюю утилиту, такую как egrep, с соответствующим регулярным выражением для поиска по определенным полям. Это будет намного быстрее.