Witam,
ostatnio otrzymałem dość ciekawe zadanie od pewnej firmy. Posiada ona gotowy skrypt, który zaczytuje pliki xlsx, xls, xml i csv do bazy danych. Na początku działało to świetnie, ale firma rozrosła się i już nie wczytują plików po 1000 wierszy a po 300 tyś. i więcej. Skrypt zwalniał tym bardziej im więcej wierszy zaczytał.
Okazało się, że problemem było logowanie komunikatów. Ktoś napisał zapytanie w następujący sposób:
UPDATE log SET log_txt = log_txt || {$statement} WHERE ...
Wiadomo jeśli skrypt wypluwał mało komunikatów baza jakoś dawała radę, ale im większy plik tym więcej komunikatów trzeba było dopisać i baza zaczęła się dławić na tym zapytaniu.
Normalnie rozwiązałbym ten problem stosując ob_start() oraz ob_get_content(). Niestety założenia są takie, że każdy komunikat ma być natychmiast wyświetlony w widoku. Wymusza to używanie ob_flush() po każdym wygenerowanym komunikacie, a co za tym idzie uniemożliwia użycie powyższej metody.
Rozwiązaniem mogłoby być dopisywanie każdego komunikatu do jakiegoś pliku za pomocą fopen z atrybutem a i fpust. Sprawdziłem i nie jest to nawet aż tak obciążające. Różnica miedzy odpaleniem skryptu wczytującego 50000 wierszy do bazy z logowaniem do pliku, a bez wynosi około pół sekundy. Niestety założenie jest takie, że wszystkie logi mają znajdować się w bazie danych, a próba zaczytania do bazy zawartości powstałego pliku wywala mi Out of Memory.
To też nie byłoby problemem ale zarząd firmy nie chce mi dać dostępu do serwera, administrator delikatnie mówiąc nie ogarnia, a próby zmiany ustawień php.ini przez ini_set(memory_limit) nie dają rezultatów (najprawdopodobniej php jest hamowany przez apache).
I tutaj w końcu pojawia się moje pytanie. Czy ma ktoś pomysł jak ugryźć ten temat z innej strony?