的表格
如果你想使用一个数组作为一个数据库,相当明显的最佳方式来模拟一个表使用一个二维数组:
$counties = array();
$countiesKey = 0;
// add a row
$counties[++$countiesKey] = array(
"name" => "Armagh",
"img" => "css/images/map.jpg",
"largeimg" => "css/images/banmap.jpg"
);
// and another...
$counties[++$countiesKey] = array(
"name" => "Antrim",
"img" => "css/images/map.jpg",
"largeimg" => "css/images/banmap.jpg"
);
这大致相当于下表定义(的缘故简单起见,我们将使用MySQL的比较,并承担所有字符串字段为VARCHAR(1024)
):
CREATE TABLE counties (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(1024),
img VARCHAR(1024),
largeimg VARCHAR(1024)
);
唯一索引
所以我们使用数组索引作为我们的主键。但为了搜索基于任何“列”非主键,将需要O(n)
操作其他数据库:我们需要遍历整个表,检查每一行的相关值。这是索引起作用的地方。如果我们想要在我们的县名上添加索引呢?那么,我们可以使用一个单独的关联数组:
关联数组被实现为一个散列表,所以访问由键的元素是大致O(1)
。这使我们能够大大加快进入行,当我们搜索的县名称:
$search = 'Antrim';
$result = array();
if (isset($countiesNameIndex[$search])) {
$result[$countiesNameIndex[$search]] = $counties[$countiesNameIndex[$search]];
}
return $result;
该指数可以动态地维持为行添加和删除:
// Insert a row
$row = array(/* row data */);
if (isset($countiesNameIndex[$row['name']])) {
// insert fails, duplicate value in column with unique index
}
$counties[++$countiesKey] = $row;
$countiesNameIndex[$row['name']] = $countiesKey;
// Delete a row
$idOfRowToDelete = 2;
if (isset($counties[$idOfRowToDelete])) {
unset(
$countiesNameIndex[$counties[$idOfRowToDelete]['name']],
$counties[$idOfRowToDelete]
);
}
该索引方法将极大地随着数据集变大,加快数据访问速度。
非聚集索引
就让我们赶快来看看我们将如何实现一个不携带它引用行的订单信息的非唯一索引 - 实现是非常相似的。这将是一个慢一点比我们的唯一指标,但明显比遍历整个数据集更快:
$countiesImgIndex = array();
// Insert a row
// INSERT INTO counties (...) VALUES (...)
$row = array(/* row data */);
if (!isset($countiesImgIndex[$row['img']])) {
$countiesImgIndex[$row['img']] = array();
}
$counties[++$countiesKey] = $row;
$countiesImgIndex[$row['img']][] = $countiesKey;
// Search using the index
// SELECT * FROM counties WHERE img = 'css/images/map.jpg'
$search = 'css/images/map.jpg';
$result = array();
if (isset($countiesImgIndex[$search])) {
foreach ($countiesImgIndex[$search] as $rowId) {
$result[$rowId] = $counties[$rowId];
}
}
return $result;
// Delete a row
// DELETE FROM counties WHERE id = 2
$idOfRowToDelete = 2;
if (isset($counties[$idOfRowToDelete])) {
$key = array_search($idOfRowToDelete, $countiesImgIndex[$counties[$idOfRowToDelete]['img']]);
if ($key !== false) {
array_splice($countiesImgIndex[$counties[$idOfRowToDelete]['img']], $key, 1);
}
unset($counties[$idOfRowToDelete]);
}
使用多个索引
我们甚至可以用这些指标来进行更复杂操作 - 考虑如何执行SQL查询
SELECT *
FROM counties
WHERE name = 'Antrim'
AND img = 'css/images/map.jpg'
首先我们来看看最具体的指数(唯一的我ndex):
$result = array();
$nameSearch = 'Antrim';
$imgSearch = 'css/images/map.jpg';
if (!isset($countiesNameIndex[$nameSearch])) {
return $result;
}
下一步,我们检查,如果该行的其他条件相匹配:
if ($counties[$countiesNameIndex[$nameSearch]]['img'] === $imgSearch) {
$result[$countiesNameIndex[$nameSearch]]
= $counties[$countiesNameIndex[$nameSearch]];
}
return $result;
你可以看到,在这种情况下,我们只需要使用1个索引,因为其中一列是查询有一个独特的索引。这意味着我们可以直接进入唯一重要的行,并检查它是否符合条件。现在让我们想象我们有另一个非唯一列的索引 - largeImg
。此操作有点复杂,但我们可以通过使用array_intersect()
走了一条捷径:
$result = array();
$imgSearch = 'css/images/map.jpg';
$largeImgSearch = 'css/images/banmap.jpg';
if (!isset($countiesImgIndex[$imgSearch], $countiesLargeImgIndex[$largeImgSearch])) {
return $result;
}
return array_intersect(
$counties[$countiesImgIndex[$imgSearch]],
$counties[$countiesLargeImgIndex[$largeImgSearch]]
);
外键和连接表
但是,当我们开始想用另一个加盟表?再一次,这很像我们在SQL中做的。让我们想象一下,我们有以下的SQL表定义:
CREATE TABLE walks (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(1024),
location VARCHAR(1024),
county INT
);
很显然,我们开始与另一个数组,并插入一些行:
$walks = array();
$walksKey = 0;
$walks[++$walksKey] = array(
"name" => "Portadown Walk",
"county" => 1,
"location" => "Portadown",
);
$walks[++$walksKey] = array(
"name" => "Antrim Walk",
"county" => 2,
"location" => "Causeway"
);
很明显这是怎么回事那里,county
列引用ID在$counties
表中的行中。顺便说一下,我们使用计数器来跟踪ID而不是使用$arr[] =
分配语法的原因有两个方面:首先,它确保从表中删除行时ID始终保持不变,其次使它更容易(计算更少昂贵的)来提取最后一个插入的行的ID - 这将有助于在使用外键创建复杂的表结构时,如您在这里看到的。
现在我们来看看将这些数据关联在一起。试想一下,我们是把这个SQL查询:
SELECT c.*, w.*
FROM walks w
JOIN counties c ON w.county = c.id
LIMIT 0, 10
这可以实现如下:
$result = array();
$i = 0;
foreach ($walks as $walkId => $walksRow) {
$result[$walkId] = array_merge($counties[$walksRow['county']], $walksRow);
if (++$i == 10) {
break;
}
}
return $result;
现在你可能已经发现这个问题:这两个表包含一个名为名称列。上面的代码将从每个行的walks
表中返回name
的值。你可以很容易地调整这种行为,但究竟如何实施将取决于你想要的结果。
排序的结果集
PHP提供了一个功能,在这里做了大部分的工作适合你 - array_multisort()
。最重要的一点是,您应该在之后应用命令来提取结果行,以最小化所需操作的数量。
SELECT c.*, w.*
FROM walks w
JOIN counties c ON w.county = c.id
ORDER BY w.location ASC
// Collect the result set in $result as above
$location = array();
foreach ($result as $row) {
$location[] = $row['name'];
}
array_multisort($location, SORT_ASC, $result);
return $result;
希望上面的例子应该开始演示一些可用于实现一些关于使用PHP阵列的RDBMS的特征的逻辑。即使数据集增长,也可以进行某些相当简单的优化,使这些操作相对便宜。
如果它真的回答了您的问题,请考虑接受答案 – michi 2013-04-14 12:37:06