在PHP-FPM处理HTTP请求时,有时会遇到一个请求需要进行多次MySQL查询(在报表类应用中比较常见)。通常我们会以串行方式查询:
$link = new mysqli()$rs1 = $link->query('SELECT * FROM table1')
while ($row = $rs1->fetch_row()) { ... }
$rs2 = $link->query('SELECT * FROM table2')
while ($row = $rs2->fetch_row()) { ... }
$rs3 = $link->query('SELECT * FROM table3')
while ($row = $rs3->fetch_row()) { ... }
串行查询方式有个缺点:在MySQL返回数据之前,PHP一直是处于空等的状态,不会继续往后执行。如果数据量大或者查询复杂,MySQL响应可能会比较慢,那么以串行方式查询会有一些延迟。给用户最直接的感受就是 Loading… 的圈圈一直打转。
那么有什么办法可以减少查询MySQL的时间?用多进程并行查询不行,因为PHP-FPM 中不允许用 pcntl_fork 一类的调用。
幸好还有 mysqlnd,mysqlnd提供了类似 stream_select 的机制(见 这篇文章) ,可以做到在单进程中对MySQL并行查询。这主要运用了mysqli_poll 和 reap_async_query 两个函数。
还是通过例子来介绍MySQL并行查询的实施方法。假设要并行地向MySQL发出10个查询,最基本的代码应该是这样的:
1. $links = []2. for ($i = 0 $i !== 10 $i++) {
3. $links[$i] = new mysqli('127.0.0.1', 'user', 'password', 'db1')
4. $links[$i]->query('SELECT SLEEP(1)', MYSQLI_ASYNC)
5. }
6. $allResult = []
7. while (!empty($links)) {
8. $reads = $links
9. $errors = $reject = []
10. if (!mysqli_poll($reads, $errors, $reject, null)) {
11. continue
12. }
13. foreach ($reads as $read) {
14. $idx = array_search($read, $links, true)
15. $allResult[$idx] = []
16. $result = $read->reap_async_query()
17. while ($row = $result->fetch_row()) {
18. $allResult[$idx][] = $row
19. }
20. $read->close()
21. unset($links[$idx])
22. }
23. }
解释下这段代码的含义:
2~5行,同时发起10个MySQL连接,并发出查询
注意query() 的第二个参数带上了 MYSQLI_ASYNC 表示非阻塞查询
10行,使用mysqli_poll 轮询10个连接的查询有无返回
mysqli_poll 的第一个参数$reads是个数组,包含需要轮询那些连接。mysqli_poll 执行完后,会改写$reads,改写后$reads包含的是那些已经有数据返回连接。
mysqli_poll的第四个参数,控制的是轮询的等待时间,单位是“秒”。如果像本例当中设置为null,那么mysqli_poll轮询是阻塞的:只有监听的连接中,任意一个连接有数据返回了,mysqli_poll才会返回。如果等待时间设置为0,那么每次执行mysqli_poll会立即返回,外层的while会频繁循环。
第11~19行,遍历已经有数据返回的连接
reap_async_query和普通query一样,返回的是mysqli_result,可以一行行fetch数据
20~21行,对于已经获得了数据的连接,下次mysqli_poll就不需要再轮询这个连接了,所以关闭连接,并从$links数组删除这个连接
当所有的连接都返回了数据,$links数组空了,while循环也就终止了。
使用并行查询的方式,可以大大缩短处理HTTP请求的时间,假设本例中的10个SQL查询,每个需要执行1秒。因为是并行,处理所有的查询,也只需要1秒左右。
//参考这个最基本的吧:<?php
$link = mysql_connect('localhost', 'root', '123456')
mysql_select_db('youdatabase', $link)
$result = mysql_query('SELECT id, title FROM table', $link)
?>
<html>
<head>
<title>文章列表</title>
</head>
<body>
<h1>文章列表</h1>
<ul>
<?php while ($row = mysql_fetch_assoc($result)): ?>
<li>
<a href="/show.php?id=<?php echo $row['id'] ?>">
<?php echo $row['title'] ?>
</a>
</li>
<?php endwhile ?>
</ul>
</body>
</html>
<?php
mysql_close($link)
php(做为现在的主流开发语言)实例教程:网站在线人数的程序代码,后台有MySQL(和PHP搭配之最佳组合)数据库支持。可以直接统计出网站当前的在线人数。首先是创建MySQL(和PHP搭配之最佳组合)数据库表。
以下是引用片段:
CREATE TABLE tablename (
field type(max_length) DEFAULT default_value (NOT) NULL
}
可以使用的SQL语句。
以下是引用片段:
CREATE TABLE useronline (
timestamp int(15) DEFAULT 0 NOT NULL,
ip varchar(40) NOT NULL,
file varchar(100) NOT NULL,
Prima(最完善的虚拟主机管理系统)RY KEY (timestamp),
KEY ip (ip),
KEY file (file)
)
下面开始使用php(做为现在的主流开发语言)脚本,首先定义MySQL(和PHP搭配之最佳组合)的信息。
以下是引用片段:
$server = "localhost"//你的服务器
$db_user = "root"//你的MySQL(和PHP搭配之最佳组合)的用户名
$db_pass = "password"//你的MySQL(和PHP搭配之最佳组合)的密码
$database = "users"//表的名字
设置统计的时间(多少秒内在线人数)
以下是引用片段:
$timeoutseconds = 300
取当前时间。
以下是引用片段:
$timestamp = time()
上面的完整代码:
以下是引用片段:
<?php(做为现在的主流开发语言)
$server = "localhost"//your server
$db_user = "root"//your MySQL(和PHP搭配之最佳组合) database username
$db_pass = "password"//your MySQL(和PHP搭配之最佳组合) database password if any
$database = "users"//the db name
$timeoutseconds = 300//timeoutseconds limit
//get the current time
$timestamp = time()
//calculate the lowest timestamp allowed
$timeout = $timestamp-$timeoutseconds
?>
连接MySQL(和PHP搭配之最佳组合)
以下是引用片段:
MySQL(和PHP搭配之最佳组合)_connect(localhost, username, password)
也允许使用变量形式。
以下是引用片段:
MySQL(和PHP搭配之最佳组合)_connect($server, $db_user, $db_pass)
如果MySQL(和PHP搭配之最佳组合)数据库没有密码的话可以使用下面代码连接(当然建议大家一定要设置好自己的密码,这样起码黑客得要解密啊)
以下是引用片段:
MySQL(和PHP搭配之最佳组合)_connect($server, $db_user)
查询数据库的代码:
以下是引用片段:
MySQL(和PHP搭配之最佳组合)_db_query(database, query)
只要有访客就要增加一条记录。
以下是引用片段:
$insert = MySQL(和PHP搭配之最佳组合)_db_query($
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)