[Laravel] MySQL LONGBLOB maximaal 1MB te downloaden

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Topicstarter
Beste PRGers.

Sinds een aantal weken ben ik aan het stoeien met Laravel (5.1). Ik ben voor een interne website een project aan het maken waarin collega's data kunnen opslaan (MySQL LONGBLOBS van ongeveer 16MB) en onze build server kan daarna deze data weer gebruiken bij het vullen van de deliverables.

De tabel is als volgt:
Table: blobstore
Columns:
id		int(10) UN AI PK
version_id	int(10) UN
size		int(10) UN
description	text
created_at	timestamp
updated_at	timestamp
raw_data	longblob


Ik kwam er bij het generen van het schema achter dat Laravel / Eloquent van zichzelf geen LONGBLOBs ondersteunt. Daarom moest ik de volgende regel toevoegen bij het aanmaken van de tabel:
[php]DB::statement("ALTER TABLE `blobstore` ADD `raw_data` LONGBLOB");[/php

Nu loop ik echter tegen een probleem aan. Wanneer ik de file download, kreeg ik maar 1MB (de eerste megabyte) van de LONGBLOB binnen.
Ik verdacht eerst de database, maar daarin staat de data wel volledig.
Afbeeldingslocatie: http://tweakers.net/ext/f/p5TmfPP0D2AHRNintmIoi8cA/thumb.png

Een korte zoektocht leidde me naar: http://stackoverflow.com/...ownload-easily-in-laravel

Omdat ik geen files had, echo-de ik de content van de raw_data direct naar de outputbuffer:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Versimpeld */
$blob = Blobstore::find($bid);
$headers = array(
            'Content-Description'       => 'File Transfer',
            'Content-Type'              => 'application/octet-stream',
            'Content-Transfer-Encoding' => 'binary',
            'Expires'                   => 0,
            'Cache-Control'             => 'must-revalidate, post-check=0, pre-check=0',
            'Pragma'                    => 'public',
            'Content-Length'            => $blob->size,
        );
$filename = 'foobar.bin';
$response = new Response('', 200, $headers);
$response->header('Content-Disposition', 'attachment; filename=' . $filename);
// If there's a session we should save it now
if (Config::get('session.driver') !== '')
{
    Session::save();
}

session_write_close();
ob_end_clean();
$response->sendHeaders();

echo $blob->raw_data;

// Finish off, like Laravel would
Event::fire('laravel.done', array($response));
$response->foundation->finish();

exit;


Middels bovenstaande code kreeg ik ook maar files van 1MB binnen.

Mogelijk was de echo $blob->raw_data; het probleem, dus verving ik de code door een tempfile:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$temp_file = tempnam(sys_get_temp_dir(), $filename);

$fp = fopen($temp_file, "w+");
flock($fp, LOCK_EX);
$writen = fwrite($fp, $blob->raw_data);
flock($fp, LOCK_UN);
fclose($fp);

if ($fp = fread($temp_file, 'rb'))
{
    while(!feof($fp) and (connection_status()==0))
    {
    print(fread($fp, 8192));
    flush();
    }
}

unlink($temp_file);

Wat schepte mijn verbazing; $writen stond op 1048576. Precies 1MB. Op dat moment begon ik Eloquent te verdenken, dus ik schreef zelf een query:
PHP:
1
2
3
4
$raw_datas = DB::select('select `raw_data` from blobstore where id = ?', [$bid]);
$raw_data = $raw_datas[0];
/* ... */
$writen = fwrite($fp, $raw_data->raw_data);

Echter hetzelfde resultaat.

Nu zit ik dus klem, wie kan mij in de juiste richting duwen?

Alvast bedankt _O_

Matis

[ Voor 7% gewijzigd door Matis op 11-08-2015 10:32 ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Nu online
Misschien een instelling van MySQL zelf?
http://dev.mysql.com/doc/...sysvar_max_allowed_packet
max_allowed_packet
Default: 1048576

You must increase this value if you are using large BLOB columns or long strings. It should be as big as the largest BLOB you want to use. The protocol limit for max_allowed_packet is 1GB. The value should be a multiple of 1024; nonmultiples are rounded down to the nearest multiple.

[ Voor 83% gewijzigd door Barryvdh op 11-08-2015 10:34 ]


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Topicstarter
Bedankt voor je snelle response, tegen deze beperking liep ik bij het opslaan van de data al aan, toevallig heb ik daar in de Coffee Corner nog een post aan geweid: Matis in "De Devschuur Coffee Corner - Iteratie ➒"

Deze heb ik al staan op
grep -Iirn max_allowed_packet /etc/mysql/my.cnf 
52:max_allowed_packet	= 128M

Dus dat is het probleem niet (meer).

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Ultimation
  • Registratie: Februari 2010
  • Laatst online: 09-09 23:29

Ultimation

Het is als Appels en peren

Maar waarom zou je (maximaal) 16Mb aan rauwe data willen opslaan in je database? Ik zou een bestand wegschrijven. Dit maakt je database alleen maar onnodig groot en langzaam.

MacBook Pro 2023 [14-inch, M2 Pro, 32GB RAM, 512GB]


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Topicstarter
Ultimation schreef op dinsdag 11 augustus 2015 @ 10:45:
Maar waarom zou je (maximaal) 16Mb aan rauwe data willen opslaan in je database? Ik zou een bestand wegschrijven. Dit maakt je database alleen maar onnodig groot en langzaam.
Heb je toevallig een bron die jouw uitspraak onderbouwd?

De data moet ik toch ergens kwijt. Daarnaast heeft de blob-kolom geen impact op de snelheid van de database, want ik spreek die kolom alleen aan wanneer ik hem daadwerkelijk wil downloaden.

Het ophalen van alle 42 rijen uit de database kost me nu 19 milliseconden.
11:19:14	select `id`, `size`, `description`, `created_at` from `blobstore` where `blobstore`.`version_id` is not null LIMIT 0, 50000	42 row(s) returned	0.019 sec / 0.000 sec


Maar dit is helemaal niet het probleem waar ik me nu druk over wil maken.

[ Voor 24% gewijzigd door Matis op 11-08-2015 11:21 ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 08-09 15:03

Douweegbertje

Wat kinderachtig.. godverdomme

MYSQL_ATTR_MAX_BUFFER_SIZE vergroten.

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Topicstarter
Douweegbertje schreef op dinsdag 11 augustus 2015 @ 11:26:
MYSQL_ATTR_MAX_BUFFER_SIZE vergroten.
Thnx, dat was inderdaad het probleem. Vreemd dat ik daar zo weinig over kon vinden. Misschien zat ik meer in de hoek van Laravel / Eloquent en MySQL te zoeken dan bij PHP / PDO zelve.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Ultimation
  • Registratie: Februari 2010
  • Laatst online: 09-09 23:29

Ultimation

Het is als Appels en peren

Matis schreef op dinsdag 11 augustus 2015 @ 11:15:
[...]

Heb je toevallig een bron die jouw uitspraak onderbouwd?

De data moet ik toch ergens kwijt. Daarnaast heeft de blob-kolom geen impact op de snelheid van de database, want ik spreek die kolom alleen aan wanneer ik hem daadwerkelijk wil downloaden.

Het ophalen van alle 42 rijen uit de database kost me nu 19 milliseconden.
11:19:14	select `id`, `size`, `description`, `created_at` from `blobstore` where `blobstore`.`version_id` is not null LIMIT 0, 50000	42 row(s) returned	0.019 sec / 0.000 sec


Maar dit is helemaal niet het probleem waar ik me nu druk over wil maken.
Snap ik. Ik heb ooit eens een site gezien waarvan ze de foto's in BLOB data in de database opslaan. Dat liep toen tegen de 10.000'en foto's aan. De logica ervan ontging mij compleet omdat men probeerde te voorkomen dat de foto's ongewenst gedownload zouden worden. Maar dat zou eerder een rechten dingetje zijn.

MacBook Pro 2023 [14-inch, M2 Pro, 32GB RAM, 512GB]


Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 08-09 15:03

Douweegbertje

Wat kinderachtig.. godverdomme

Dat is geen rechten dingetje.
Een foto die je laat zien, is altijd te downloaden. Dat kun je nooit tegengaan, ook niet door het opslaan van BLOB's, want immers worden dat uiteindelijk weer images.

De enige oplossing is niet de echte afbeelding laten zien, denk hierbij aan een watermerk, of een hele lage resolutie. Vervolgens in een beschermde omgeving (denk na betaling of w/e) kun je de echte laten zien.

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Topicstarter
De rechten zijn bij mij het probleem niet. Iedereen kan alles zien en kan zoveel blobs opslaan als hij zelf wil.
Het feit dat ik er voor gekozen heb om ze in een database op te slaan en niet op filesystem is het feit dat de database-server wel gebackupped wordt en het filesystem(web)-server niet.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 08-09 15:03

Douweegbertje

Wat kinderachtig.. godverdomme

Ja mij hoor je niet klagen. Iedereen heeft zijn eigen afwegingen gemaakt (hopelijk) om een gedegen oplossing te gebruiken.

Er zijn voor beide kanten voor- en nadelen te bedenken. Het enige wat me een beetje dwars zou zitten is dat je al één file hebt van 16Mb. Nu maakt het maar 3 bytes uit of je TINYBLOB of LONGBLOB gaat gebruiken, maar de daadwerkelijke data is natuurlijk relatief groot.
Stel dat je 1000 'images' hebt a 16Mb dan zit je op ~15.6Gb in je database..

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:54

Janoz

Moderator Devschuur®

!litemod

Maar je hebt 'in je database' en 'in je database'. In de daadwerkelijke implementatie van MySQL is het zeer waarschijnlijk zo dat de daadwerkelijke blobdata alsnog apart opgeslagen wordt. Het zit iig niet tussen de rest van de records gegevens.

Waar ik me in dit specifieke geval meer zorgen om zou maken is dat je al je data in je geheugen aan het laden bent door het gebruik van Laravel en/of php. Zeker met zoveel data is het veel handiger om gewoon een stream te gebruiken, maar dit wordt niet door php ondersteund.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • borft
  • Registratie: Januari 2002
  • Laatst online: 11-09 15:55
Ik vermoed dat de grote mysql results ook de query cache van mysql om zeep helpen. en wat Janoz zegt, query resultaten worden meestal client side gebufferd! Als je gewoon van disk leest en direct output, heb je dat niet nodig!

Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 08-09 15:03

Douweegbertje

Wat kinderachtig.. godverdomme

Janoz schreef op dinsdag 11 augustus 2015 @ 17:09:
Maar je hebt 'in je database' en 'in je database'. In de daadwerkelijke implementatie van MySQL is het zeer waarschijnlijk zo dat de daadwerkelijke blobdata alsnog apart opgeslagen wordt. Het zit iig niet tussen de rest van de records gegevens.

Waar ik me in dit specifieke geval meer zorgen om zou maken is dat je al je data in je geheugen aan het laden bent door het gebruik van Laravel en/of php. Zeker met zoveel data is het veel handiger om gewoon een stream te gebruiken, maar dit wordt niet door php ondersteund.
PDO PARAM_LOB is wel degelijk een stream.

Ja ik heb een MSSQL en MYSQL wrapper geschreven.. ik weet bijna alles nu :+

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Topicstarter
Ik weet niet precies hoe MySQL de blobs fysiek opslaat. Dat kan ik morgen nog wel eens uitzoeken.

Wel weet ik al dat we FPGAs hebben waarvan de RBF (programmeer file) al 22MB aantikt. Die moeten dus ook opgeslagen gaan worden. Dus die 16MB is al geen heilige grens meer.

Het enige dat ik nog kan "normaliseren" is de blob alleen met z'n blobstore.ID opslaan in een aparte tabel. Al weet ik niet of dat nog wat gaat brengen qua performance. Ik heb nu alle select queries op die tabel al expliciet gemaakt exclusief de raw_data, behalve natuurlijk bij het downloaden.

Is dat nog de moeite waard?

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 08-09 15:03

Douweegbertje

Wat kinderachtig.. godverdomme

Meten is weten. :)

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:54

Janoz

Moderator Devschuur®

!litemod

Douweegbertje schreef op dinsdag 11 augustus 2015 @ 17:46:
[...]


PDO PARAM_LOB is wel degelijk een stream.

Ja ik heb een MSSQL en MYSQL wrapper geschreven.. ik weet bijna alles nu :+
Werkt dat nu eindelijk? Ik ging een beetje uit van https://bugs.php.net/bug.php?id=40913 .

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 08-09 15:03

Douweegbertje

Wat kinderachtig.. godverdomme

Janoz schreef op woensdag 12 augustus 2015 @ 09:25:
[...]


Werkt dat nu eindelijk? Ik ging een beetje uit van https://bugs.php.net/bug.php?id=40913 .
oh sick. Dat wist ik niet :+
Geen idee of het werkt. Eerlijk gezegd gebruik ik geen standaard drivers en heb ik niet alle functies getest, alleen (grotendeels) geïmplementeerd :p
Pagina: 1