1

我正在做大约 600 个INSERT ON DUPLICATE KEY UPDATE查询,其中每个插入可以有一组不同的列。

我现在这样做的方式只是一个带有mysql_query(). 真的很慢,由于最大执行时间为 30 秒,php 脚本停止了。

我不能使用INSERT INTO table (columns) VALUES (values 1), (values 2), ..., (values n),因为每个插入必须能够有一组不同的列。

我还查看了准备好的查询,但从我所见,它似乎也不适用于不同的列集。

我是数据库和 MYSQL 的新手。我只是在拼凑一些东西作为周末项目,现在我只想让项目的最后一部分工作。我很抱歉没有以正确的方式做到这一点。(很抱歉也使用了已弃用的 php mysql 函数。)也许我应该去睡觉,稍后再重写。正确的方法是什么?

编辑:这是有关表格类型的一些信息

-- phpMyAdmin SQL 转储
-- 版本 3.5.1
-- http://www.phpmyadmin.net
--
-- 主机:本地主机
-- 生成时间:2012 年 7 月 22 日晚上 9:59
-- 服务器版本:5.5.24-log
-- PHP版本:5.3.13

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

--
-- 数据库:`trailerbay`
--

-------------------------------------------------- --------

--
-- 表`movies`的表结构
--

如果不存在“电影”,则创建表(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `imdb` int(7) NOT NULL,
  `title` 文本整理 utf8_unicode_ci,
  `releasedate` 日期 DEFAULT NULL,
  `enlistdate` 日期时间不为空,
  `runtime` 时间 DEFAULT NULL,
  `trailer` 文本 COLLATE utf8_unicode_ci NOT NULL,
  `plot` 文本整理 utf8_unicode_ci,
  `cover` 文本 COLLATE utf8_unicode_ci NOT NULL,
  主键(`id`),
  唯一键`id`(`id`),
  唯一键 `imdb` (`imdb`)
) 引擎=InnoDB 默认字符集=utf8 排序=utf8_unicode_ci AUTO_INCREMENT=1145 ;
4

3 回答 3

1

我不认为你可以在表中有这么多列,它们的开/关组合非常多。

因此,对于每一行,您可以提取其列组合(例如,您可以按字母顺序对字段进行排序)并将其结构用作键:

// $tuple has been sorted based on keys

$syndrome = implode(',', array_keys($tuple));

$values = array_values($tuple);    

if (isset($big_inserts[$syndrome]))
    array_push($big_inserts[$syndrome], $values);
else
    $big_inserts[$syndrome] = array($values);

在循环结束时,您会发现自己拥有一个$big_inserts包含一定数量键的数组。每个键将映射一组值,适用于多次插入。

除非您真的非常不走运,否则您的“多个插入”将比您开始使用的单个插入少得多。如果所有插入具有相同的列,那么 big_inserts 中将只有一个键,保存所有元组。

现在,在 big_inserts 上循环,您可以为每个键准备一个语句。要发送到 PDO 的值数组是 中所有元组的串联$big_inserts[$key]

foreach($big_inserts as $fields => $lot)
{
    $SQL = "INSERT INTO table ($fields) VALUES ";
    // I need a (?.?.?---) tuple
    $tuple = '('.implode(',', array_fill(0, count($lot[0]), '?')).')';
    // How many tuples are in a lot?
    $SQL .= implode(',', array_fill(0, count($lot), $tuple));
    $values = array();
    foreach($lot as $set)
        $values = array_merge($values, $set);
    // Now $SQL has all the '?'s, and $values contains all the values.
    // Run the statement.
 }

如果这还不够,您可能必须将语句分成块,将它们保存在会话中并按顺序执行每个块,可能使用单独的表来模拟“多往返”事务(以防连接丢失/用户关闭浏览器/无论一半的块已经执行,另一半还没有完成。使用直接插入到具有相同结构的表中,然后当表准备好时,在事务中运行一个 INSERT INTO ... SELECT FROM 并删除辅助提交后的表。

如果它们是简单的 INSERT,我会尝试暂时禁用一些索引,但您依赖它们进行 ON DUPLICATE KEY UPDATE,所以这是不行的。

于 2012-07-22T22:02:12.117 回答
0

只需一次将其拆分为 50 个插入,将其划分为 12 个文件并按顺序执行它们。简单的 javascript 在完成时重定向到下一个。

如果它只是一次性交易,那可能是最简单的解决方案。

否则发布一些示例代码,以便我们提供一些更有帮助的答案。

于 2012-07-22T21:48:35.257 回答
0

您的插入是否在 mysql 事务中执行?如果没有,这可能有助于提高您的性能。

http://kevin.vanzonneveld.net/techblog/article/improve_mysql_insert_performance/

于 2012-07-22T21:56:09.610 回答