【问题标题】:Most Efficient Way To Poll Database Using SSE使用 SSE 轮询数据库的最有效方法
【发布时间】:2021-02-18 15:47:52
【问题描述】:

我觉得这一定是一个被解决了一百万次的问题,但是经过三个小时的搜索,我找不到答案。我试图弄清楚如何仅在 Mysql 表中发生更改时将数据发送到客户端,并以最有效的方式进行。

对于流式音频播放器上的“正在播放”功能,我需要在每次歌曲更改时使用艺术家和歌曲标题数据更新

标签。我正在使用 JQuery + Ajax 来执行此操作,但这似乎效率极低,因此我切换到服务器发送事件。我的服务器端代码如下。

但是,这似乎只是稍微高效一些,因为除非我的理解不正确,否则我的代码每五秒发送一次相同的艺术家歌曲数据,即使正在播放的歌曲没有变化。

<?php

//include db connect file
if (!isset($pdo)) {
include '../../PDO_con.inc';
}

//run a query to get the most recent song for today
$statement = $pdo->query('[SELECT most recent record in table]');

while($row = $statement->fetch(PDO::FETCH_ASSOC)) {

    $artist = $row['artist_name'];
    $song   = $row['title'];
    $song_data = $artist . " - " . $song;

}

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Access-Control-Allow-Origin: *');

echo "retry: 5000\ndata: {$song_data}\n\n";
flush();

?>

似乎我应该每 5 秒一次又一次地运行选择查询(也许通过将其包装在 WHILE 循环中?),但仅在发生更改时发送 SSE 数据。我应该能够自己解决这个问题,但到目前为止我还没有找到答案。感谢您的任何建议。

编辑:作为对评论的回应,这里是选择最新记录的查询:

'SELECT artist.artist_name, song.title, plays.play_date FROM plays INNER JOIN song ON plays.song_id = song.id INNER JOIN artist ON song.artist_id = artist.id WHERE date(plays.play_date) = date(now()) ORDER BY plays.play_date DESC LIMIT 1';

我所说的效率是指仅在发生变化的地方发送数据。现在,我的脚本每 5 秒发送一次数据,无论它是否已更改。客户端的

标记使用相同的数据更新现有数据,直到发生更改。因此,对于一分钟的歌曲,艺术家+标题数据被发送 12 次。这似乎是对互联网资源的浪费,尽管我认为考虑到互联网流量的总量,这可能是一种微不足道的浪费。

【问题讨论】:

  • 更新或插入表格后,只要表格发生变化,就可以使用套接字进行更新
  • 最好理解您所说的最有效以及选择最新条目的查询是什么意思。
  • 我在 10 天前answered a similar question,在那里我建议使用一个小文件,而不是轮询数据库。我在那里使用了时间信号,但你可以将歌曲数据放在那个文件中。这个想法并不完美,但至少您不会经常轮询数据库。

标签: php mysql server-sent-events


【解决方案1】:

只要您有某种方法可以确定哪些记录需要从数据库推送到客户端,您就可以定期轮询数据库。根据数据库设计的复杂性,您可能需要考虑其他优化,例如缓存。

只要连接打开,您就可以执行无限循环。每 5 秒轮询一次数据库以查看是否有任何新条目。跟踪您最近进行的一项调查。

这是一个非常粗略的例子:

<?php

header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");

$pdo = new \PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", 'user', 'password', [
    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
    \PDO::ATTR_EMULATE_PREPARES => false
]);

$lastTime = new DateTime('1 minute ago');
$stmt = $pdo->prepare('SELECT message, created_at FROM messages WHERE created_at>? ORDER BY created_at');

while (!connection_aborted()) {
    $stmt->execute([$lastTime->format('Y-m-d H:i:s')]);

    foreach ($stmt as $message) {
        $lastTime = new DateTime($message['created_at']);
        echo 'data: This is a message at time ' . $lastTime->format('Y-m-d H:i:s') . "\n\n";
    }

    ob_flush();
    flush();

    sleep(5);
}

每 5 秒轮询一次数据库并没有那么糟糕。普通用户每秒可以刷新几次页面,因此您的服务器应该可以轻松地处理每 5 秒一次的轮询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-27
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    • 2014-02-13
    相关资源
    最近更新 更多