如何优化Php mysql查询以更快地执行

如何优化Php mysql查询以更快地执行,php,mysql,optimization,Php,Mysql,Optimization,使用php脚本将数据从一个数据库复制到另一个数据库。它工作得很好,但需要很多时间。大约每分钟插入1000行,这意味着复制100000行最多需要2小时!可以通过优化以下代码来减少此时间吗?试图删除子查询并放置左联接,但无效 编辑-脚本根据单词或其组合从一个数据库db1中选择数据。它使用爆炸/内爆进行匹配。然后,它在其他db2数据库中创建该名称的新表。然后将所选数据插入新数据库db2。现在,它正在从旧数据库的两个表中选择数据。它正在为此使用子查询。使用left join会加快执行速度吗 我的代码 &

使用php脚本将数据从一个数据库复制到另一个数据库。它工作得很好,但需要很多时间。大约每分钟插入1000行,这意味着复制100000行最多需要2小时!可以通过优化以下代码来减少此时间吗?试图删除子查询并放置左联接,但无效

编辑-脚本根据单词或其组合从一个数据库db1中选择数据。它使用爆炸/内爆进行匹配。然后,它在其他db2数据库中创建该名称的新表。然后将所选数据插入新数据库db2。现在,它正在从旧数据库的两个表中选择数据。它正在为此使用子查询。使用left join会加快执行速度吗

我的代码

<?php
ini_set('max_execution_time', 30000); 
ini_set('default_charset',"utf-8");

include('config_collect.php');
header('Content-Type: text/html; charset=utf-8');

$keywordId = $_GET['id'];
require_once("config_duplicate.php");
?>

<?php 

try
{
$kewyQ = $db->query("SELECT * FROM collections where id = 
$keyId"); 
$kVal = $kewyQ->fetch(PDO::FETCH_ASSOC);
$table = trim($kVal['words']);

//Create table
$Q = "CREATE TABLE IF NOT EXISTS `$table` (
`id` INT AUTO_INCREMENT NOT NULL,
`t_id` bigint(20) NOT NULL,
`t_text` TEXT,
`user_name` varchar(100),
`place` varchar(100),
`time` datetime,
`description` TEXT,
PRIMARY KEY (`id`)) 
CHARACTER SET utf8 COLLATE utf8_general_ci";
$db2->query($Q);

// Count all records based on words
if (preg_match('/\s/',$table)) {
$keySpace = explode(" ", $table);
if(count($keySpace) > 1){
    $squery = "SELECT * FROM t WHERE t_text LIKE 
 '%".implode("%' AND t_text LIKE '%", $keySpace)."%' ";
 }else{
    $keyval = $keySpace[0];
    $squery = "SELECT * FROM t WHERE t_text LIKE '%$keyval%' ";
 }
 }else{
$squery = "SELECT * FROM t WHERE t_text LIKE '%$tablename%'";
}

在我公司的最后两个项目中,我不得不处理类似的案例。 我们必须通过网络复制大约1000万行数据,想到的第一个解决方案是使用php。这种做法显然失败了

相反,我用这段代码替换了它,因为它是纯mysql,所以运行速度惊人

$this->logger->info('Dumping the data');
    $biDbUser = $this->getContainer()->getParameter('bi_database_user');
    $biDbPass = $this->getContainer()->getParameter('bi_database_password');
    $biDbHost = $this->getContainer()->getParameter('bi_database_host');
    $biDbName = $this->getContainer()->getParameter('bi_database_name');
    $dumpFilePath = rtrim(sys_get_temp_dir(), '/').'/'.uniqid('init_dump_bi').'.sql';

    exec(sprintf(
        'mysqldump -u %s -p%s -h %s --single-transaction --compress %s %s > %s',
        $biDbUser,
        $biDbPass,
        $biDbHost,
        $biDbName,
        $contextConfig->getBiTableLast(),
        $dumpFilePath
    ));
    $this->logger->info('Dump completed. Now loading it to our db.');

    $dpDbUser = $this->getContainer()->getParameter('dp_database_user');
    $dpDbPass = $this->getContainer()->getParameter('dp_database_password');
    $dpDbHost = $this->getContainer()->getParameter('dp_database_host');
    $dpDbName = $this->getContainer()->getParameter('dp_database_name');
    exec(sprintf(
        'cat %s | mysql -u %s -p%s -h %s %s',
        $dumpFilePath,
        $dpDbUser,
        $dpDbPass,
        $dpDbHost,
        $dpDbName
    ));


    unlink($dumpFilePath);

    $columns = array_diff($contextConfig->getColumns(), ['timestamp']);
    $query = sprintf(
        'INSERT INTO %s (%s) SELECT %s FROM %s',
        $contextConfig->getInvoicingTable(),
        implode(',', $columns),
        implode(',', $columns),
        $contextConfig->getBiTableLast()
    );

    $this->logger->info('Data moved to our db. Now inserting from bi to our table.');
    exec(sprintf('mysql -u %s -p%s -h %s %s -e "%s"', $dpDbUser, $dpDbPass, $dpDbHost, $dpDbName, $query));
    $this->logger->info('Insert done.');


    $query = 'DROP TABLE '.$contextConfig->getBiTableLast();
    exec(sprintf('mysql -u %s -p%s -h %s %s -e "%s"', $dpDbUser, $dpDbPass, $dpDbHost, $dpDbName, $query));

    $this->logger->info('Finished synchronisation BI->DP.', [
        'context' => $contextConfig->getContextCode()
    ]);
显然,我不打算解释很多变量,但这里是这个脚本的主要部分

exec(sprintf(
        'mysqldump -u %s -p%s -h %s --single-transaction --compress %s %s > %s',
        $biDbUser,
        $biDbPass,
        $biDbHost,
        $biDbName,
        $contextConfig->getBiTableLast(),
        $dumpFilePath
    ));
我从symfony获得连接配置(在您的情况下,您应该从您的连接获得它),并调用mysqldump。我使用--single事务,因为用户具有只读访问权限。同时使用--compress可以避免给数据中心网络带来太大的压力

exec(sprintf(
        'cat %s | mysql -u %s -p%s -h %s %s',
        $dumpFilePath,
        $dpDbUser,
        $dpDbPass,
        $dpDbHost,
        $dpDbName
    ));
使用此命令完成转储后,您将把转储的数据放入目标数据库。 最后

$query = sprintf(
        'INSERT INTO %s (%s) SELECT %s FROM %s',
        $contextConfig->getInvoicingTable(),
        implode(',', $columns),
        implode(',', $columns),
        $contextConfig->getBiTableLast()
    );

    $this->logger->info('Data moved to our db. Now inserting from bi to our table.');
    exec(sprintf('mysql -u %s -p%s -h %s %s -e "%s"', $dpDbUser, $dpDbPass, $dpDbHost, $dpDbName, $query));
我使用mysql insert select查询将数据从新转储的表传递到我们的表。 我尝试使用pdo连接来执行最后一个调用,但我猜在mysql的所有会话都可以全局使用该表之前,会有一个延迟。所以PDO一直说找不到桌子


希望能有所帮助。

计划A:

将所有行从一个表复制到另一个表的最快方法是在单个查询中执行:

INSERT INTO new (a,b,c)
    SELECT a,b,c FROM old;
没有行计数,没有循环,MySQL和PHP之间没有来回,等等

我不清楚你到底在做什么,但看看你是否能从这个目标上后退

方案B:

由于您似乎正在浏览一大堆表格,因此这可能会更好:

在PHP之外,做什么

mysqldump ... old_db  |  mysql ... new_db
注意:这也可以为新的数据库提供相同的
创建表

方案C:

这是上述两种方法的结合。它为传输创建一个CSV文件

SELECT a,b,c FROM old_tbl INTO OUTFILE ...;
LOAD DATA INFILE ...;
更多(查看示例SQL后)

是否有多个由
$table
表示的“相同”表格?如果是这样的话,这是模式设计中的一个大危险信号;请解释你的意图

嗯,我不喜欢使用
单词
集合
,但这将插入与两个选项结合起来:

INSERT INTO  $table
      ( t_id, t_text, user_name, time,
        description, place ) 
SELECT  t.t_id, t.t_text, t.user_name, t.time,
        u.description, u.place
    FROM  t
    JOIN  users u  ON u.user_name = t.user_name
    WHERE  t_text LIKE '%blue%'
      AND  t_text LIKE '%car%' ;

我不太熟悉这种类型的代码。你能提供任何链接来记录同样的内容吗?你能告诉我如何在我的代码中使用左连接而不是子查询吗?对不起,这里没有这样的文档:)这里也没有子查询,这只是给你一个想法。代码不是那么简单。脚本根据单词或它们的组合从一个数据库db1中选择数据。它使用爆炸/内爆进行匹配。然后,它在其他db2数据库中创建该名称的新表。然后将所选数据插入新数据库db2。现在,它正在从旧数据库的两个表中选择数据。它正在为此使用子查询。使用left join会加快执行速度吗?也许您可以向我们展示每个SQL语句的示例?@RickJames SELECT*来自id=30的集合;选择*FROM t,其中t_文本如“%red%”和t_文本如“%car%”;选择描述,从用户处放置user_name=
Rick
;将值('30'、'Nice red and big car'、'Rick'、'California'、'2017/06/03'、'developer')插入
$表中
SELECT a,b,c FROM old_tbl INTO OUTFILE ...;
LOAD DATA INFILE ...;
INSERT INTO  $table
      ( t_id, t_text, user_name, time,
        description, place ) 
SELECT  t.t_id, t.t_text, t.user_name, t.time,
        u.description, u.place
    FROM  t
    JOIN  users u  ON u.user_name = t.user_name
    WHERE  t_text LIKE '%blue%'
      AND  t_text LIKE '%car%' ;