Мне нужно вставить 29000 строк в 2 DB: TimescaleDB и Influx на моем локальном компьютере (Ubuntu 20.04 8GB Ram)
Когда я вставляю в приток, это довольно быстро. Я делаю это с помощью службы Golang, которая разбивает данные на части из 10000 строк и вставляет их в поток. это занимает 256 мс
Но вставить в TimescaleDB совсем другое дело. Сначала я использую Laravel 8 / PHP8. Может быть, не самый быстрый, но я застрял с ним.
Затем я вставляю куски по 100 строк с функцией upsert()
.
Это занимает 22 минуты для 29000 строк. Я использую linux-valet, который использует сервер nginx, php8 и postgres / timescaleDB 12.
Я попытался воспроизвести свои производственные настройки, в моем .env я установил
APP_ENV=production
APP_DEBUG=false
И я казнил php artisan optimize
Еще 22 мин.
В производстве у меня нет этой проблемы, потому что я вставляю только 5648 строк, и это занимает 123 мс для inlux и 1 секунду для TimescaleDB. Единственная разница, я полагаю, заключается в том, что в производственной среде я все еще использую PHP7.4
Как для локальной, так и для производственной среды конфигурация timescaleDB является конфигурацией по умолчанию.
Я понимаю, что Laravel медленна для массовой вставки и что Go намного быстрее для этой задачи.
Почему такая разница и что мне сделать, чтобы она стала быстрее?
РЕДАКТИРОВАТЬ: добавлен фрагмент кода Laravel для вставки в TimescaleDB:
public function store(Request $request)
{
ini_set('max_execution_time', -1);
$body = $request->getContent();
$meter = json_decode($body, true);
$chunkSize = 100;
$measures = $meter['Measures'];
$chunkedRaws = collect($measures)->chunk($chunkSize);
$ok = 0;
$nok = 0;
foreach ($chunkedRaws as $raws) {
$raws = $raws->map(function ($raw) use ($meter) {
if (!isset($raw['s'])) {
$source = "Pamela";
} else {
$source = $raw['s'];
}
return new \App\Models\Raw([
'operation_id' => $meter['OperationID'],
'meter_id' => $meter['ID'],
'conso_prod' => $meter['ConsoProd'],
'timestep' => $meter['Timestep'],
'unit' => $meter['Unit'],
'source' => $source,
'time' => Carbon::parse($raw['t'])->toIso8601ZuluString(),
'delta' => $raw['d'],
]);
})->toArray();
try {
DB::disableQueryLog();
$raws = collect($raws)->unique(function ($item) { // eliminate duplicates
return $item['time'] . $item['operation_id'] . $item['meter_id'] . $item['conso_prod'];
})->toArray();
DB::table('raws')->upsert($raws, ['time', 'operation_id', 'meter_id', 'conso_prod'], ['delta']);
// DB::table('raws')->insert($raws);
$ok += $chunkSize;
} catch (PDOException $e) {
$nok += $chunkSize;
Log::warning($e->getMessage());
}
}
return response()->json(['message' => $ok . " Raws has been inserted,\n " . $nok . " Failed"], 200);
}
echo time()
вдоль вашего кода (до и после->map
, до и после->unique
, до и после->upsert
) и проверьте, какой шаг занимает больше всего времени, и если он почти одинаков для каждого фрагмента, чтобы изолировать проблему. Laravel и Nginx, вероятно, не являются частью проблемы. Шансы выше в конфигурации шкалы времени, проблеме с драйвером БД, ограничении сети или машины базы данных (оперативная память / диск). - person Felippe Duarte   schedule 03.02.2021