Php 从另一个表的大型子集中不存在的大型表中删除记录
下面是ma方法Symfony,删除其ID不存在于其他表中的Etitities的原则,该表包含了几种不同类型的ID列表。精确到6,但重要的是只了解系统的结构 并且,除非使用包含大约300000条记录的实体参数调用该方法,并且辅助表“oId”具有相似数量的记录,否则所有操作都是完美的。因此,该方法应该只删除我之前解释过的几条记录,当所有记录都工作到50000以下的表时,这里我遇到了数据库中的问题: SQLSTATE[HY000]:一般错误:超过1205锁等待超时;尝试重新启动事务 此错误不会与以前的实体一起出现。 我不知道问题出在哪里,因为记录的数量只大十倍,所以当这些查询在几秒钟内执行时,为什么我在20秒后看不到结果。? 这种错误的背后是什么 我甚至重建了我的方法,以循环方式完成任务,正如在一些关于如何从表中删除大量记录的回答中所说的那样。此外,我还将限制降低到1000条记录,所有记录都正常运行,除非它使用前面描述的实体开始运行 这里是整个方法 还有一点解释。不要害怕sql注入。$typeId和$borderId来自数据库,而不是来自用户Php 从另一个表的大型子集中不存在的大型表中删除记录,php,mysql,symfony,doctrine-orm,bigdata,Php,Mysql,Symfony,Doctrine Orm,Bigdata,下面是ma方法Symfony,删除其ID不存在于其他表中的Etitities的原则,该表包含了几种不同类型的ID列表。精确到6,但重要的是只了解系统的结构 并且,除非使用包含大约300000条记录的实体参数调用该方法,并且辅助表“oId”具有相似数量的记录,否则所有操作都是完美的。因此,该方法应该只删除我之前解释过的几条记录,当所有记录都工作到50000以下的表时,这里我遇到了数据库中的问题: SQLSTATE[HY000]:一般错误:超过1205锁等待超时;尝试重新启动事务 此错误不会与以前的
/**
* Deletes records from given entity which are not exists in imported csv file.
*
* @param string $entity
* @param integer $typeId
* @param int $borderId Additional condition. Eg. 5 means, none of entities below id of value 5 will be delted (id < 5)
*/
public function removeNonExistent($entity, $typeId, $borderId = null)
{
$subQueryQb = $this->repository->createQueryBuilder('oId');
$subQueryQb->select('oId.originalId')
->andWhere('oId.type = '.$typeId)
//->andWhere('oId.originalId = e.originalId')
//Uncomment to have subquery of EXIST rather the IN()
;
$qb = $this->em->createQueryBuilder();
$qb->select('min(e.id) as minId, max(e.id) as maxId, count(e.id) as countId');
$qb->from($entity, 'e');
$tableData = $qb->getQuery()->getArrayResult();
$queries = 0;
$limit = 1000;
$id = $tableData[0]['minId'];
while ($id < $tableData[0]['maxId']) {
$deleteQb = $this->em->createQueryBuilder();
$deleteQb->delete()
->from($entity, 'e')
->andWhere('e.id BETWEEN '.$id.' AND '.($id + $limit - 1))
->andWhere($deleteQb->expr()->notIn('e.originalId', $subQueryQb→getDQL())) //Comment to use subquery as EXIST rather than IN()
//->andWhere($deleteQb->expr()->not($deleteQb->expr()->exists($subQueryQb->getDQL())))
//Uncomment to use subquery as EXIST rather than IN()
;
if ($borderId !== null) {
$deleteQb->andWhere('e.id > '.$borderId);
}
$qResult = $deleteQb->getQuery()->getResult();
$this->em->flush($entity);
$queries++;
echo $queries.'# delete query executed. Rows deleted: '.$qResult."\n";
$id += $limit;
if ($tableData[0]['countId'] < $limit) {
break;
}
}
echo $queries.' delete queries executed.'."\n";
}
有人能帮忙吗?我很乐意得到任何线索。我发现的第一件事是这个查询的最后一行
DELETE FROM table
WHERE id NOT IN (
SELECT a.original_id
FROM table_ids a
WHERE a.type = 6
)
AND id > 3
如果查询的表单没有最后一行,那么我们仍然在谈论MySQL5.6
DELETE FROM table
WHERE id NOT IN (
SELECT a.original_id
FROM table_ids a
WHERE a.type = 6
)
– (without last this line)
id计数约为30万且此行排除的查询执行速度非常快,约为几秒钟,但如果我添加该行且id>3,则所有查询都会减慢甚至停止。
所以这是解决方案,但我必须有这个条件
现在是解决方案二:
/**
* Deletes records from given entity which are not exists in imported csv file.
*
* @param string $entity
* @param integer $typeId
* @param int $borderId Additional condition. Eg. 5 means, none of entities below id of value 5 will be delted (id < 5)
*/
public function removeNonExistent($entity, $typeId, $borderId = null)
{
$metaData = $this->em->getClassMetadata($entity);
$mainMetaData = $this->em->getClassMetadata($this->class);
$connection = $this->em->getConnection();
$connection->query('BEGIN;');
$connection->query('CREATE TABLE '.$metaData->getTableName().'_copy LIKE '.$metaData->getTableName().';');
$connection->query('INSERT INTO '.$metaData->getTableName().'_copy
SELECT *
FROM '.$metaData->getTableName().'
WHERE '.$metaData->getTableName().'.'.$metaData->getColumnName('originalId').' IN (
SELECT '.$mainMetaData->getColumnName('originalId').' FROM '.$mainMetaData->getTableName().' WHERE '.$mainMetaData->getColumnName('type').' = '.$typeId.'
)
;');
if ($borderId !== null) {
$connection->query('INSERT INTO '.$metaData->getTableName().'_copy
SELECT *
FROM '.$metaData->getTableName().'
WHERE '.$metaData->getTableName().'.'.$metaData->getColumnName('id').' <= '.$borderId.';');
}
$connection->query('RENAME TABLE '.$metaData->getTableName().' TO '.$metaData->getTableName().'_old, '.$metaData->getTableName().'_copy TO '.$metaData->getTableName().';');
$connection->query('
ALTER TABLE '.$metaData->getTableName().' DISABLE KEYS;
SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET AUTOCOMMIT = 0;
;');
$connection->query('DROP TABLE '.$metaData->getTableName().'_old;');
$connection->query('
SET UNIQUE_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 1;
ALTER TABLE '.$metaData->getTableName().' ENABLE KEYS;
;');
$connection->query('COMMIT;');
}
简而言之:
我们将数据复制到新的tmp表中,然后更改名称并返回以前的顺序
现在它开始工作了。
唯一的缺点是我必须在不添加外键的情况下重建数据库的模式
我只想知道为什么这条简单的线还有一个条件
id>3
使查询无法完成
最后有一点需要澄清:
当我第一次执行问题中的脚本时,我不想在执行查询时等待太久,所以我输入^C。每次出现超时错误时。只有第一次,并没有错误,也并没有影响,更重要的是结束了
就是这样。使用迭代之间的睡眠这有这么简单吗?现在我无法检查,但我会尽快检查。我相信就是这样。提前谢谢!请向我们展示结果SQL。不要在选择中使用。。。它可能比LEFT JOIN慢。使用自动提交,不是一个大交易。@McClayin我更改了它并添加了sleep1,但将限制更改为31000,我不知道如果限制为31000,为什么会收到27个查询。表中有大约321000条记录。另一件奇怪的事情是,在登录后的第一次运行脚本时,我进入了27个查询,脚本被挂起,再也没有继续。在第二次运行中,它挂起并在执行开始时超越错误。甚至没有一行喜欢d delete查询。。。这是条令,它生成了查询,所以我认为在代码中,构造查询所需的全部内容都给出了。根据LEFT JOIN的说法,我不知道它应该是什么样子,所以你能给我一些样品吗?根据autocommit,正如doctrine文档中所写,默认情况下,连接以自动提交模式运行,这意味着它是非事务性的,除非您通过beginTransaction显式启动事务,否则我对该行为没有任何更改。我之前的评论中的信息也适用于此评论。谢谢你的帮助!