Эффективный способ поиска значения на основе ключа в php - PullRequest
4 голосов
/ 23 декабря 2010

Имея список из примерно 100 000 пар ключ / значение (обе строки, в основном около 5-20 символов каждая), я ищу способ эффективного поиска значения для данного ключа.

Это нужно сделать на сайте php. Я знаком с хеш-таблицами в Java (что, вероятно, я бы сделал, если бы работал в Java), но я новичок в php.

Я ищу советы о том, как сохранить этот список (в текстовом файле или в базе данных?) И выполнить поиск в этом списке.

Список должен периодически обновляться, но меня больше всего интересует время поиска.

Ответы [ 3 ]

13 голосов
/ 23 декабря 2010

Вы можете сделать это как обычный массив PHP, но Sqlite станет вашим лучшим выбором для скорости и удобства, если он доступен.

массив PHP

Просто сохраните все в php-файле следующим образом:

<?php
return array(
    'key1'=>'value1',
    'key2'=>'value2',
    // snip
    'key100000'=>'value100000',
);

Тогда вы можете получить к нему доступ так:

<?php
$s = microtime(true); // gets the start time for benchmarking

$data = require('data.php');
echo $data['key2'];

var_dump(microtime(true)-$s); // dumps the execution time

Не самая эффективная вещь в мире, но она сработает. На моей машине это занимает 0,1 секунды.

Sqlite

PHP должен поставляться с включенным sqlite, который отлично подойдет для такого рода вещей.

Этот сценарий создаст для вас базу данных от начала до конца с характеристиками, подобными данным, которые вы описали в вопросе:

<?php
// this will *create* data.sqlite if it does not exist. Make sure "/data" 
// is writable and *not* publicly accessible.
// the ATTR_ERRMODE bit at the end is useful as it forces PDO to throw an
// exception when you make a mistake, rather than internally storing an
// error code and waiting for you to retrieve it.
$pdo = new PDO('sqlite:'.dirname(__FILE__).'/data/data.sqlite', null, null, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));

// create the table if you need to
$pdo->exec("CREATE TABLE stuff(id TEXT PRIMARY KEY, value TEXT)");

// insert the data
$stmt = $pdo->prepare('INSERT INTO stuff(id, value) VALUES(:id, :value)');
$id = null;
$value = null;

// this binds the variables by reference so you can re-use the prepared statement
$stmt->bindParam(':id', $id);
$stmt->bindParam(':value', $value);

// insert some data (in this case it's just dummy data)
for ($i=0; $i<100000; $i++) {
    $id = $i;
    $value = 'value'.$i;
    $stmt->execute();
}

А затем использовать значения:

<?php
$s = microtime(true);

$pdo = new PDO('sqlite:'.dirname(__FILE__).'/data/data.sqlite', null, null, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));

$stmt = $pdo->prepare("SELECT * FROM stuff WHERE id=:id");
$stmt->bindValue(':id', 5);
$stmt->execute();

$value = $stmt->fetchColumn(1);

var_dump($value);

// the number of seconds it took to do the lookup
var_dump(microtime(true)-$s);

Это ваааааааааааа. 0,0009 секунд на моей машине.

MySQL

Вы могли бы также использовать MySQL для этого вместо Sqlite, но если это всего лишь одна таблица с описанными вами характеристиками, вероятно, это будет излишним. Приведенный выше пример Sqlite будет отлично работать с MySQL, если у вас есть сервер MySQL. Просто измените строку, которая создает экземпляр PDO, на это:

$pdo = new PDO('mysql:host=your.host;dbname=your_db', 'user', 'password', array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));

Запросы в примере sqlite должны нормально работать с MySQL, но учтите, что я не проверял это.

Давайте немного сойдем с ума: безумие файловой системы

Не то, чтобы решение Sqlite было медленным (0,0009 секунд!), Но это примерно в четыре раза быстрее на моей машине. Кроме того, Sqlite может быть недоступен, настройка MySQL может быть невозможной и т. Д.

В этом случае вы также можете использовать файловую систему:

<?php
$s = microtime(true); // more hack benchmarking

class FileCache
{
    protected $basePath;

    public function __construct($basePath)
    {
        $this->basePath = $basePath;
    }

    public function add($key, $value)
    {
        $path = $this->getPath($key);
        file_put_contents($path, $value);
    }

    public function get($key)
    {
        $path = $this->getPath($key);
        return file_get_contents($path);
    }

    public function getPath($key)
    {
        $split = 3;

        $key = md5($key);
        if (!is_writable($this->basePath)) {
            throw new Exception("Base path '{$this->basePath}' was not writable");
        }
        $path = array();
        for ($i=0; $i<$split; $i++) {
            $path[] = $key[$i];
        }
        $dir = $this->basePath.'/'.implode('/', $path);
        if (!file_exists($dir)) {
            mkdir($dir, 0777, true);
        }
        return $dir.'/'.substr($key, $split);
    }
}

$fc = new FileCache('/tmp/foo');

/*
// use this crap for generating a test example. it's slow to create though.
for ($i=0;$i<100000;$i++) {
    $fc->add('key'.$i, 'value'.$i);
}
//*/

echo $fc->get('key1', 'value1');

var_dump(microtime(true)-$s);

Этот поиск занимает 0,0002 секунды для поиска на моей машине. Это также дает преимущество, заключающееся в том, что он достаточно постоянен независимо от размера кэша.

1 голос
/ 23 декабря 2010

Это зависит от того, как часто вы будете получать доступ к вашему массиву, подумайте так, сколько пользователей могут получить к нему доступ одновременно. Существует много преимуществ для хранения его в базе данных, и здесь у вас есть два варианта MySQL и SQLite.

SQLite работает больше как текстовый файл с поддержкой SQL, вы можете сэкономить несколько миллисекунд во время запросов, так как он находится в пределах досягаемости вашего приложения, основным недостатком которого является то, что он может добавлять только одну запись за раз (так же, как текстовый файл) , Я бы порекомендовал SQLite для массивов со статическим содержимым, таких как данные GEO IP, переводы и т. Д.

MySQL является более мощным решением, но требует аутентификации и находится на отдельной машине.

0 голосов
/ 23 декабря 2010

PHP массивы сделают все, что вам нужно. Но не должно ли столько данных храниться в базе данных?

http://php.net/array

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...