odbc_exec 执行简单查询需要很长时间
Posted
技术标签:
【中文标题】odbc_exec 执行简单查询需要很长时间【英文标题】:odbc_exec taking a long time to execute a simple query 【发布时间】:2014-01-17 13:08:11 【问题描述】:我一直在更新 php 脚本以使用 .mdb Access 2010 数据库,并且我发现 odbc_exec 命令需要很长时间才能执行。我正在运行的 SQL 查询是:
SELECT MIN(ID) AS fd FROM myTable WHERE ID > 3572 AND ( [field2] LIKE '%TEXT%')
SELECT MAX(ID) AS fd FROM myTable WHERE ID < 3572 AND ( [field2] LIKE '%TEXT%')
SELECT COUNT(*) AS fd FROM myTable WHERE ID <= 3572 AND ( [field2] LIKE '%TEXT%')
SELECT COUNT(*) AS fd FROM myTable WHERE ( [field2] LIKE '%TEXT%')
它们用于我正在更新的搜索结果分页系统。 我的 php 代码是这样的:
$sql = "SELECT MIN(ID) AS fd FROM myTable WHERE ID > 3572 AND ( [field2] LIKE '%TEXT%')"
$sqlconn = odbc_connect("my_data_source","","",SQL_CURSOR_FORWARD_ONLY);
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
// more code using $data
当我运行我的代码时,我发现它需要几分钟才能运行,这太长了。通过注释掉它之后的所有内容,我已经将罪魁祸首找到了$result = odbc_exec($sqlconn, $sql);
行。我对 php 和 odbc 连接还很陌生,到目前为止,我还没有找到为什么需要这么长时间的原因。直接在数据库上运行查询几乎是瞬时的。
myTable
是数据库中的一个表,包含大约 60,000 条记录和 25 列数据。它没有我知道的主键字段或任何索引,尽管添加主键似乎不会对运行时间产生任何重大影响。
我已经尝试过的一些事情包括将 ODBC 数据源缓冲区大小从 2048 增加到 4096,在数据库中的 ID 字段上添加主键,以及使用 SQL_CUR_USE_ODBC
游标选项而不是 SQL_CURSOR_FORWARD_ONLY
选项。
更新 我不知道这是否相关,但是当从 php 文件运行查询时,我注意到一些奇怪的事情。 .mdb 数据库与其他几个 .mdb 数据库位于一个文件夹中,当查询运行时,它们中的每一个都被锁定(具有随附的 .ldb 文件)。它还导致 Apache 运行非常缓慢。
我不知道要发布哪些其他相关信息,所以如果我遗漏了什么,请告诉我。
【问题讨论】:
Like '%...' 可能会很慢,因为它不会使用索引。 .mdb 文件是否在执行 PHP 脚本的机器的本地驱动器上? @GordThompson 是的,这一切目前都在我的本地机器上运行。 re: 多个 .ldb 文件 - PHP 脚本完成后是否所有 .ldb 文件都消失了? 是否有可能获得一个 sargable 子集/子表并将 Like 应用于那个? 【参考方案1】:显然LIKE '%TEXT%'
条件是瓶颈,它强制对每个查询进行表扫描。如果这些LIKE
条件对于每批四个查询总是相同的(即,为相同的记录子集获取四个值),那么使用临时表会有很大帮助。
对于有 60,000 条记录的测试表,以下代码在我最旧和最破旧的测试盒上运行大约需要 10 或 11 秒:
$sql = "SELECT MIN(ID) AS fd FROM myTable WHERE ID > 3572 AND ( [field2] LIKE '%TEXT%')";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v1 = $data['fd'];
$sql = "SELECT MAX(ID) AS fd FROM myTable WHERE ID < 3572 AND ( [field2] LIKE '%TEXT%')";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v2 = $data['fd'];
$sql = "SELECT COUNT(*) AS fd FROM myTable WHERE ID <= 3572 AND ( [field2] LIKE '%TEXT%')";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v3 = $data['fd'];
$sql = "SELECT COUNT(*) AS fd FROM myTable WHERE ( [field2] LIKE '%TEXT%')";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v4 = $data['fd'];
但是,以下代码在同一台机器上只需 1 或 2 秒即可完成:
$tempTableName = uniqid();
$sql = "CREATE TABLE $tempTableName (ID INTEGER PRIMARY KEY)";
$result = odbc_exec($sqlconn, $sql);
$sql =
"INSERT INTO $tempTableName (ID) " .
"SELECT ID FROM myTable WHERE ( [field2] LIKE '%TEXT%')";
$result = odbc_exec($sqlconn, $sql);
$sql = "SELECT MIN(ID) AS fd FROM $tempTableName WHERE ID > 3572";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v1 = $data['fd'];
$sql = "SELECT MAX(ID) AS fd FROM $tempTableName WHERE ID < 3572";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v2 = $data['fd'];
$sql = "SELECT COUNT(*) AS fd FROM $tempTableName WHERE ID <= 3572";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v3 = $data['fd'];
$sql = "SELECT COUNT(*) AS fd FROM $tempTableName";
$result = odbc_exec($sqlconn, $sql);
$data = odbc_fetch_array($result);
odbc_free_result($result);
$v4 = $data['fd'];
$sql = "DROP TABLE $tempTableName";
$result = odbc_exec($sqlconn, $sql);
【讨论】:
以上是关于odbc_exec 执行简单查询需要很长时间的主要内容,如果未能解决你的问题,请参考以下文章