【发布时间】:2016-06-09 00:58:41
【问题描述】:
尝试编写一些东西来自动从一些任意的 DB 结果(即并非总是来自表 x)转换为适当的 PHP 类型结果。
我扩展了 PDOStatement 类,
class Statement extends PDOStatement {
protected $pdo;
protected $transformer;
protected function __construct(PDO $pdo) {
$this->pdo = $pdo;
$this->transformer = $pdo->getTransformer();
}
public function fetchAll() {
$results = parent::fetchAll(PDO::FETCH_ASSOC);
if ($this->getTransformer()) $results = $this->completeResults($results);
return $results;
}
private function completeResults(array $results = []) {
if ($results == null || count($results) == 0) return null;
if ($results[0] == false || !is_array($results[0])) return null;
$index = 0;
$typeMap = [];
foreach ($results[0] as $column => $result) {
$meta = $this->getColumnMeta($index); // this is very painful
$typeMap[$column] = $meta['native_type'];
$index++;
}
$transformer = $this->getTransformer();
foreach ($results as $index => &$result) {
array_walk($result, function(&$value, $key) use ($typeMap, $transformer) {
$type = $typeMap[$key];
$value = $transformer->transformToPhpValue($value, $type);
});
}
return $results;
}
}
以前,在我意识到 PDO 抽象之前,我使用的是(在我的特定情况下)标准的 pg_...() 方法。使用pg_field_type($resource, $column);可以获取列类型,速度比较快。
现在,使用新的(对我而言)PDO 方法。如果我注释掉我进行转换的代码部分,并运行 7 个连续查询:
time to complete: 9.5367431640625E-7 seconds
time to complete: 1.1920928955078E-6 seconds
time to complete: 9.5367431640625E-7 seconds
time to complete: 0 seconds
time to complete: 9.5367431640625E-7 seconds
time to complete: 0 seconds
time to complete: 0 seconds
启用它:
time to complete: 0.5777850151062 seconds
time to complete: 0.49124097824097 seconds
time to complete: 0.28375911712646 seconds
time to complete: 0.5946729183197 seconds
time to complete: 0.42177200317383 seconds
time to complete: 5.0067901611328E-6 seconds
time to complete: 0.42121982574463 seconds
那是/疯狂/。
通过查看我的 Postgres 日志,我可以知道它正在一一获取列信息:
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=1114
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=1114
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=25
... like 30 more of these ...
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=25
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=23
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=23
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=23
查询的复杂程度从
SELECT
p.modified_at, ... ~ 30 fields ..., r.level AS id_level
FROM table_p AS p
LEFT JOIN table_a AS a ON (p.owner = a.id)
LEFT JOIN table_a0 AS a0 ON (p.reporter = a0.id)
LEFT JOIN table_r AS r ON (p.id = r.id)
WHERE (p.id = 1)
只给SELECT * FROM table_a AS a;
所以,我想问题是:有没有更好的方法来做到这一点?有没有办法在不影响代码速度的情况下做到这一点? 7 个查询处于每个请求运行的连续查询的低端,所以这是我想要处理的事情。
【问题讨论】:
-
我相信就目前而言,你最好使用 php 来做,因为它仍然是实验性的。会快一光年。
-
如果你打算在你的项目中只使用 Postgresql,我强烈建议你使用原生 pgsql 库来代替 PDO。 PDO 速度较慢,并且公开的功能较少。您的类型问题的答案可能是stackoverflow.com/questions/31643297/…
-
@greg 是的,这就是我以前使用的。不幸的是,这意味着要编写很多 PDO 附带的功能......
-
@greg 此外,大部分功能都被包装在依赖注入类中,因此明确使用 postgres 不是一种选择。
-
我认为您可以显式编写查询,这样您就不必循环和获取每个列数据类型。一个 SELECT 语句使用尽可能多的列,并使用
pg_typeof()函数将每一列包装起来。
标签: php postgresql pdo