Вот лучший метод, который я когда-либо придумал, и я хотел бы знать, есть ли еще лучший метод (я уверен, что есть!) Для хранения и выборки миллионов пользовательских изображений:
Чтобы уменьшить размеры каталогов и избежать дополнительных вызовов к БД, я использую вложенные каталоги, которые рассчитываются на основе уникального идентификатора пользователя следующим образом:
$firstDir = './images';
$secondDir = floor($userID / 100000);
$thirdDir = floor(substr($id, -5, 5) / 100);
$fourthDir = $userID;
$imgLocation = "$firstDir/$secondDir/$thirdDir/$fourthDir/1.jpg";
Идентификаторы пользователя ($userID
) варьируются от 1 до миллионов.
Так, например, если у меня есть идентификатор пользователя 7654321
, первое изображение этого пользователя будет сохранено в:
./images/76/543/7654321/1.jpg
Для идентификатора пользователя 654321
:
./images/6/543/654321/1.jpg
Для идентификатора пользователя 54321
это будет:
./images/0/543/54321/1.jpg
Для идентификатора пользователя 4321
это будет:
./images/0/43/4321/1.jpg
Для идентификатора пользователя 321
это будет:
./images/0/3/321/1.jpg
Для идентификатора пользователя 21
это будет:
./images/0/0/21/1.jpg
Для идентификатора пользователя 1
это будет:
./images/0/0/1/1.jpg
Это гарантирует, что при наличии 100 000 000 пользователей у меня никогда не будет каталога с более чем 1000 подкаталогами, поэтому, похоже, он будет чистым и эффективным.
Я сравнил этот метод с использованием следующего метода «хэширования», который использует самый быстрый метод хэширования, доступный в PHP (crc32). Этот метод «хэширования» вычисляет Второй каталог как первые 3 символа в хэше идентификатора пользователя и Третий каталог как следующие 3 символа для распределения файлов случайным образом, но равномерно, следующим образом:
$hash = crc32($userID);
$firstDir = './images';
$secondDir = substr($hash,0,3);
$thirdDir = substr($hash,3,3);
$fourthDir = $userID;
$imgLocation = "$firstDir/$secondDir/$thirdDir/$fourthDir/1.jpg";
Однако этот метод хеширования медленнее, чем метод, описанный выше, поэтому он бесполезен.
Затем я пошел еще дальше и нашел еще более быстрый способ вычисления Третьего справочника в моем исходном примере (floor(substr($userID, -5, 5) / 100);
) следующим образом:
$thirdDir = floor(substr($userID, -5, 3));
Теперь это меняет то, как / где хранятся первые 10000 идентификаторов пользователя, и некоторые третьи каталоги имеют либо 1 пользовательский подкаталог, либо 111 вместо 100, но преимущество в том, что он быстрее, так как нам не нужно делить на 100, так что я думаю, что в конечном итоге это того стоит.
Как только структура каталогов определена, вот как я планирую хранить фактические отдельные изображения: например, если пользователь загружает 2-е изображение, оно будет находиться в том же каталоге, что и его первое изображение, но будет иметь имя 2.jpg
. Изображение пользователя по умолчанию всегда будет просто 1.jpg
, поэтому, если он решит сделать 2-е изображение изображением по умолчанию, 2.jpg
будет переименовано в 1.jpg
, а 1.jpg
будет переименовано 2.jpg
. * 1056. *
И последнее, но не менее важное: если бы мне нужно было хранить несколько размеров одного и того же изображения, я бы сохранил их следующим образом для идентификатора пользователя 1 (например):
1024px:
./images/0/0/1/1024/1.jpg
./images/0/0/1/1024/2.jpg
640px:
./images/0/0/1/640/1.jpg
./images/0/0/1/640/2.jpg
Вот и все.
Итак, есть ли недостатки этого метода? Если да, не могли бы вы указать на них?
Есть ли лучший метод? Если да, не могли бы вы описать это?
Прежде чем приступить к реализации этого, я хочу убедиться, что у меня есть лучший, самый быстрый и самый эффективный способ хранения и извлечения изображений, чтобы мне не пришлось его менять снова.
Спасибо!