重写数据库查询

时间:2018-06-02 17:53:35

标签: php mysql mysqli

我有PHP脚本,每5分钟运行一次,从API获取数据,然后将其写入MySQL表。我的网站的用户(300+)可以通过数据表查询该数据,其他页面显示一些数据。 然后PHP脚本获取API数据

foreach($array as $row)
{
    $query .= "INSERT INTO table_name 
    (
        col_name1, 
        col_name2, 
        col_name3, 
        col_name4, 
        col_name5
    ) 
    VALUES
    (
        '".$row["value1"]."', 
        '".$row["value2"]."', 
        '".$row["value3"]."', 
        '".$row["value4"]."', 
        '".$row["value5"]."'
    );";
}

mysqli_query($connect, "DELETE FROM table_name");

mysqli_multi_query($connect, $query);
每次脚本运行时,

DELETE然后INSERT到该空表中。 该表有1000行,这将随着时间的推移而增长。 我收到的报告显示数据表有时是空的,在出现任何内容之前,他们必须刷新几次。

是否有更好的方法来构建数据库,表和/或查询。

1 个答案:

答案 0 :(得分:1)

为每一行运行单独的插入语句会非常缓慢。

运行多插入,使用单个语句插入多行会更有效。例如,使用单个语句插入四行。

INSERT INTO t (a,b,c) VALUES (?,?,?) ,(?,?,?) ,(?,?,?) ,(?,?,?)

一个潜在的缺点是,如果一行由于错误而无法插入,则整个语句将被回滚,并且没有任何行被插入。

SQL语句的最大长度受max_allowed_packet限制。没有必要在单个语句中插入所有行。在pop中插入10行会显着减少语句执行次数。

假设该表使用InnoDB存储引擎...

如果我们禁用自动提交,并在单个事务的上下文中运行DELETE语句和INSERT语句,那么该表将不会好像是空的"到其他会议。其他会话将继续在DELETE之前看到表格的内容......直到COMMIT完成。

代码模式似乎容易受到SQL注入攻击。 (尤其是使用多查询时会产生很多肮脏的东西。

减轻SQL注入的最佳做法是使用带有绑定占位符的预准备语句。

https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet

修改

作为替代方法,如果表具有主键或唯一键,请考虑

加载临时表(不是目标表)。

然后运行语句以应用更改以使目标表与临时表同步。我们将通过名称来源引用临时表。

- 更新现有行

 UPDATE target t 
   JOIN source s
     ON s.id = t.id
    SET t.col = s.col 
      , t.foo = s.foo
      , t.bar = s.bar

- 插入新行

INSERT INTO target
SELECT s.*
  FROM ( SELECT r.*
           FROM source r
             -- anti-join 
           LEFT
           JOIN target q
             ON q.id = r.id 
          WHERE q.id IS NULL
        ) s

- 删除已删除的行

 DELETE t.*
   FROM target t
     -- anti-join
   LEFT
   JOIN source s
     ON s.id = t.id
  WHERE s.id IS NULL 

这样可以避免空白"目标表,因此并发SELECT语句仍将返回行,而目标表正在"同步' d"。

针对目标表的DML UPDATE / INSERT / DELETE操作可以在单个事务的上下文中执行。