如何从PHP快速创建多个略有不同的插入

时间:2012-07-22 21:42:09

标签: php mysql

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

我现在这样做的方式只是一个mysql_query()的foreach循环。它真的很慢,php脚本由于最长执行时间30秒而停止。

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

我还查看了准备好的查询,但从我看到的情况来看,似乎不适用于不同的列集。

我是数据库和MYSQL的新手。我只是将一些东西作为一个周末项目进行黑客攻击,而现在我只想让这个项目的最后一部分工作。对不这样做,我很抱歉。 (抱歉使用已弃用的php mysql函数。)也许我应该去睡觉并稍后重写。这样做的正确方法是什么?

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

-- phpMyAdmin SQL Dump
-- version 3.5.1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Jul 22, 2012 at 09:59 PM
-- Server version: 5.5.24-log
-- PHP Version: 5.3.13

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

--
-- Database: `trailerbay`
--

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

--
-- Table structure for table `movies`
--

CREATE TABLE IF NOT EXISTS `movies` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `imdb` int(7) NOT NULL,
  `title` text COLLATE utf8_unicode_ci,
  `releasedate` date DEFAULT NULL,
  `enlistdate` datetime NOT NULL,
  `runtime` time DEFAULT NULL,
  `trailer` text COLLATE utf8_unicode_ci NOT NULL,
  `plot` text COLLATE utf8_unicode_ci,
  `cover` text COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`),
  UNIQUE KEY `imdb` (`imdb`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1145 ;

3 个答案:

答案 0 :(得分: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到具有相同结构的表中,然后当表准备就绪时,在事务中运行一个INSERT INTO ... SELECT FROM提交后删除辅助表。

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

答案 1 :(得分:0)

一次将其分成50个插入,将其分成12个文件并按顺序执行。简单的javascript,可以在完成时重定向到下一个。

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

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

答案 2 :(得分:0)

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

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