Pertanyaan Bagaimana saya bisa mengakses data dalam banyak file CSV besar dengan cepat dari Perl?


Saya memiliki sejumlah skrip yang saat ini dibaca dalam banyak data dari beberapa file .CSV. Untuk efisiensi, saya menggunakan Teks :: CSV_XS modul untuk membacanya dan kemudian membuat hash menggunakan salah satu kolom sebagai indeks. Namun, saya punya banyak file dan mereka cukup besar. Dan masing-masing skrip perlu membaca data lagi.

Pertanyaannya adalah: Bagaimana saya bisa terus-menerus menyimpan hash Perl ini sehingga semuanya dapat dibaca kembali dengan minimum CPU?

Menggabungkan skrip bukan merupakan pilihan. Saya harap...

Saya menerapkan aturan optimasi ke-2 dan menggunakan profil untuk menemukan bahwa sebagian besar CPU (sekitar 90%) berada di:

Text::CSV_XS::fields
Text::CSV_XS::Parse
Text::CSV_XS::parse

Jadi, saya membuat skrip uji yang dibaca di semua file .CSV (Teks :: CSV_XS), membuangnya menggunakan Bisa disimpan modul, dan kemudian kembali dan membacanya kembali menggunakan Bisa disimpan modul. Saya membuat profil ini sehingga saya bisa melihat waktu CPU:

$ c:/perl/bin/dprofpp.bat
Total Elapsed Time = 1809.397 Seconds
  User+System Time = 950.5560 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 25.6   243.6 243.66    126   1.9338 1.9338  Storable::pretrieve
 20.5   194.9 194.92 893448   0.0002 0.0002  Text::CSV_XS::fields
 9.49   90.19 90.198 893448   0.0001 0.0001  Text::CSV_XS::Parse
 7.48   71.07 71.072    126   0.5641 0.5641  Storable::pstore
 4.45   42.32 132.52 893448   0.0000 0.0001  Text::CSV_XS::parse
 (the rest was in terms of 0.07% or less and can be ignored)

Jadi, menggunakan Bisa disimpan biaya sekitar 25,6% untuk memuat kembali dibandingkan dengan Teks :: CSV_XS sekitar 35%. Tidak banyak tabungan ...

Ada yang punya saran bagaimana saya bisa membaca data ini lebih efisien?

Terima kasih atas bantuan Anda.


7
2017-07-24 20:34


asal


Jawaban:


Mengurai data sekali dan memasukkannya ke dalam Db SQLite. Kueri menggunakan DBI.


9
2017-07-24 20:40



Cara termudah untuk menempatkan hash yang sangat besar pada disk, IMHO, adalah dengan BerkeleyDB. Ini cepat, waktu-diuji dan rock-solid, dan modul CPAN menyediakan API yang diikat. Itu berarti Anda dapat terus menggunakan hash Anda seolah-olah itu adalah struktur data di memori, tetapi secara otomatis akan membaca dan menulis melalui BerkeleyDB ke disk.


11
2017-07-24 21:58



Yah, saya telah mengambil saran dari Sinan Ünür (terima kasih!) Dan membuat database SQLite dan menjalankan kembali program pengujian saya untuk membandingkan mendapatkan data melalui file CSV dibandingkan dengan mendapatkan data dari basis data SQLite:

$ c:/perl/bin/dprofpp.bat
Total Elapsed Time = 1705.947 Seconds
  User+System Time = 1084.296 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 19.5   212.2 212.26 893448   0.0002 0.0002  Text::CSV_XS::fields
 15.7   170.7 224.45    126   1.3549 1.7814  DBD::_::st::fetchall_hashref
 9.14   99.15 99.157 893448   0.0001 0.0001  Text::CSV_XS::Parse
 6.03   65.34 164.49 893448   0.0001 0.0002  Text::CSV_XS::parse
 4.93   53.41 53.412 893574   0.0001 0.0001  DBI::st::fetch
   [ *removed the items of less than 0.01 percent* ]

Total untuk CSV_XS adalah 34.67% dibandingkan dengan 20.63% untuk SQLite yang agak lebih baik daripada solusi Storable yang saya coba sebelumnya. Namun, ini bukan perbandingan yang adil karena dengan solusi CSV_XS saya harus memuatnya seluruh File CSV tetapi dengan antarmuka SQLite, saya bisa memuat bagian yang saya inginkan. Jadi dalam prakteknya, saya mengharapkan lebih banyak perbaikan daripada yang ditunjukkan oleh tes yang berpikiran sederhana ini.

Saya belum mencoba menggunakan BerkeleyDB (maaf, friedo) daripada SQLite, kebanyakan karena saya tidak melihat saran itu sampai saya terlibat dengan mencoba SQLite. Menyiapkan tes adalah tugas yang tidak sepele karena saya hampir tidak pernah memiliki kesempatan untuk menggunakan database SQL.

Namun, solusinya jelas untuk memuat semua data ke dalam database dan akses melalui modul DBI. Terima kasih atas bantuan semua orang. Semua tanggapan sangat dihargai.


3
2017-07-27 18:32



Jauh lebih baik untuk tidak menarik seluruh daftar ke dalam memori setiap kali Anda menjalankan skrip. Menggunakan database on-disk akan memungkinkan Anda untuk melakukan ini. Jika, karena alasan tertentu, Anda harus menyentuh setiap entri dalam file CSV setiap kali Anda menjalankan, saya mungkin menyarankan untuk menyimpannya di disk RAM daripada disk fisik. Ini jelas cocok dalam memori, saya tidak berpikir Anda akan mendapatkan banyak perbaikan dengan mengubah format on-disk yang Anda simpan. Satu-satunya cara untuk mempercepatnya adalah menyimpannya pada media yang lebih cepat.


2
2017-07-24 21:07



Jika Anda hanya perlu mengakses sebagian data di setiap skrip, alih-alih SEMUA itu, DBM :: Deep mungkin adalah taruhan terbaik Anda.

Disk / IO kemungkinan akan menjadi penghambat terbesar Anda, tidak peduli apa pun yang Anda lakukan. Mungkin Anda bisa menggunakan penyedia data yang menyimpan semua data yang tersedia dalam cache yang disembunyikan - menggunakan sesuatu seperti Sys :: Mmap :: Simple Saya tidak pernah perlu melakukan hal semacam ini, jadi saya tidak punya banyak hal lain untuk ditawarkan.


1
2017-07-24 22:28