php - SQL INSERT INTO SELECT 并返回 SELECT 数据以创建行 View 计数

标签 php mysql sql

因此,我正在创建一个系统,该系统将一次从表中提取 50-150 条记录并将它们显示给用户,并且我试图为每条记录保留一个 View 计数。

我认为最有效的方法是创建一个 MEMORY 表,我使用 INSERT INTO 将行的 ID 拉入其中,然后有一个 cron 函数定期运行以聚合 View ID 计数并清除内存表,用最新的 View 计数更新原始表。这避免了不断更新可能最常访问的表,因此我不会在每个查询中一次锁定 150 行(如果我使用 MyISAM,则不会锁定整个表)。

基本上,方法解释了here .

但是,我当然希望在提取记录信息以供查看的同时执行此操作,并且我希望避免运行第二个单独的查询只是为了获取相同的计数数据集.

有没有办法选择一个数据集,返回该数据集,并同时将该数据集中的单个列插入到另一个表中?

看起来 PostgreSQL 可能有类似于我想要的带有 RETURNING 关键字的东西,但我使用的是 MySQL。

最佳答案

首先,我不会在 Main 表中添加计数器列。我将创建一个单独的 Audit 表,该表将保存 Main 表中项目的 ID 加上该 ID< 时的至少时间戳 被请求。本质上,Audit 表将存储请求的历史记录。在这种方法中,您可以轻松生成更有趣的报告。您始终可以计算每个项目的总计,也可以按天、周、月等计算每个项目或所有项目的摘要。根据数据量,您可以定期删除早于某个阈值(一个月、一年等)的审核条目。

此外,您可以根据需要轻松地将更多信息存储在 Audit 表中,例如,用户 ID 以计算每个用户的统计信息。

要“自动”填充Audit 表,我会创建一个存储过程。客户端代码将调用此存储过程而不是执行原始的 SELECT。存储过程将返回与原始 SELECT 完全相同的结果,但还会向客户端代码透明地向 Audit 表添加必要的详细信息。

因此,让我们假设 Audit 表如下所示:

CREATE TABLE AuditTable
(
    ID int 
    IDENTITY -- SQL Server
    SERIAL -- Postgres
    AUTO_INCREMENT -- MySQL
    NOT NULL,
    ItemID int NOT NULL,
    RequestDateTime datetime NOT NULL
)

你的主要 SELECT 看起来像这样:

SELECT ItemID, Col1, Col2, ...
FROM MainTable
WHERE <complex criteria>

要在 SQL Server 中的一条语句中同时执行 INSERTSELECT,我会在 Postgres 中使用 OUTPUT 子句 - RETURNING 子句,在 MySQL 中 - ???我不认为它有这样的东西。因此,MySQL 过程将有几个单独的语句。

MySQL

首先执行您的SELECT 并将结果插入temporary (可能是内存)表。然后将项目 ID 从临时表复制到 Audit 表中。然后从临时表中SELECT返回结果给客户端。

CREATE TEMPORARY TABLE TempTable
(
    ItemID int NOT NULL,
    Col1 ..., 
    Col2 ..., 
    ...
)
ENGINE = MEMORY
SELECT ItemID, Col1, Col2, ...
FROM MainTable
WHERE <complex criteria>
;

INSERT INTO AuditTable (ItemID, RequestDateTime)
SELECT ItemID, NOW()
FROM TempTable;

SELECT ItemID, Col1, Col2, ...
FROM TempTable
ORDER BY ...;

SQL Server(只是逗你玩。这个语句同时执行 INSERTSELECT)

MERGE INTO AuditTable
USING
(
    SELECT ItemID, Col1, Col2, ...
    FROM MainTable
    WHERE <complex criteria>
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT
    (ItemID, RequestDateTime)
VALUES
    (Src.ItemID, GETDATE())
OUTPUT
    Src.ItemID, Src.Col1, Src.Col2, ...
;

您可以让Audit 表保持原样,或者您可以设置cron 来定期汇总它。这实际上取决于数据量。在我们的系统中,我们将单独的行存储一周,此外我们每小时汇总统计数据并将其保留 6 周,此外我们将每日汇总保留 18 个月。但是,重要的是,所有这些摘要都是单独的 Audit 表,我们不会在 Main 表中保留审计信息,因此我们不需要更新它。

Joe Celko 在 SQL Style Habits: Attack of the Skeuomorphs 中解释得很好:

Now go to any SQL Forum text search the postings. You will find thousands of postings with DDL that include columns named createdby, createddate, modifiedby and modifieddate with that particular meta data on the end of the row declaration. It is the old mag tape header label written in a new language! Deja Vu!

The header records appeared only once on a tape. But these meta data values appear over and over on every row in the table. One of the main reasons for using databases (not just SQL) was to remove redundancy from the data; this just adds more redundancy. But now think about what happens to the audit trail when a row is deleted? What happens to the audit trail when a row is updated? The trail is destroyed. The audit data should be separated from the schema. Would you put the log file on the same disk drive as the database? Would an accountant let the same person approve and receive a payment?

关于php - SQL INSERT INTO SELECT 并返回 SELECT 数据以创建行 View 计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32281469/

相关文章:

php - 从数组中加载特定数据

MySQL:列大小限制

mysql - 设置和清除 MySQL 中存储为整数的多个位

sql - phpMyAdmin 4.8.4 导出表,因为缺少 SQL

mysql选择不在时间段内的行(由两列定义)

php - 在 PHP 中模拟值类型结构类

php - 使用 Zend 框架的 iPhone Web 服务

sql - View 上的查询运行速度比直接查询慢 - 在 Oracle 中

带有 IntlDateFormatter 的 PHP

mysql - 如何只更新时间戳的日期部分?