mysql选择删除

mysql选择删除,mysql,Mysql,编辑: 我在这里找到了解决办法 假设select需要很长时间才能执行,那么它会很长时间锁定表吗 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT foo FROM bar WHERE wee = 'yahoo!'; DELETE FROM bar WHERE wee = 'yahoo!'; COMMIT; 设置会话事务隔离级别可重复读取; 启动交易; 从wee='yahoo!'所在

编辑: 我在这里找到了解决办法 假设select需要很长时间才能执行,那么它会很长时间锁定表吗

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT foo FROM bar WHERE wee = 'yahoo!'; DELETE FROM bar WHERE wee = 'yahoo!'; COMMIT; 设置会话事务隔离级别可重复读取; 启动交易; 从wee='yahoo!'所在的栏中选择foo; 从wee='yahoo!'所在的栏中删除; 犯罪 我希望使用一个条件来选择mysql中的行,将它们作为resultset返回到我的应用程序,然后删除这些行。如何做到这一点?我知道我可以做到以下几点,但效率太低了:

select * from MyTable t where _critera_. //get the resultset and then delete from MyTable t where t.id in(...result...) 从MyTable t中选择*,其中_critera。 //获取结果集,然后 从MyTable t中删除,其中t.id位于(…结果…)
我需要使用事务处理吗?有单一的查询解决方案吗?

没有单一的查询解决方案。使用

select * from MyTable t where _critera_
//get the resultset and then
delete from MyTable where _critera_

使用WHERE子句执行SELECT语句,然后在DELETE语句中使用相同的WHERE子句。假设数据没有临时更改,则应删除相同的行

编辑:是的,您可以将其设置为单个事务,以便在执行此操作时不会修改表

我需要使用事务处理吗?是否有单一的查询解决方案

是的,您需要使用事务。不能在单个查询中删除和选择行(即,无法“返回”或“选择”已删除的行)

您不一定需要执行
可重复读取
选项-我相信您也可以选择行
进行更新
,尽管这是更高级别的锁定<代码>可重复读取似乎是安全执行此事务所需的最低锁定级别。它恰好是InnoDB的默认值

这对表的影响程度取决于
wee
列上是否有索引。如果没有它,我相信MySQL将不得不锁定整个表

进一步阅读:


执行select语句。在循环过程中,创建唯一ID的列表字符串。然后使用IN将此列表传递回mySQL。

我需要
根据某些条件选择一些行,对数据执行一些操作,然后
以原子方式删除这些行,也就是说,不删除任何符合条件但在
选择
之后插入的行

与其他答案相反,
可重复阅读
不够。提到请特别注意此标注:

数据库状态的快照适用于事务中的
SELECT
语句,而不一定适用于DML语句。如果插入或修改某些行,然后提交该事务,则从另一个并发的
可重复读取
事务发出的
DELETE
UPDATE
语句可能会影响那些刚刚提交的行,即使会话无法查询它们

你可以自己试试:

首先创建一个表:

CREATE TABLE x (i INT NOT NULL, PRIMARY KEY (i)) ENGINE = InnoDB;
启动事务并检查表(现在称为会话1):

启动另一个会话(会话2)并插入一行。注意:此会话处于自动提交模式

您将看到新插入的行。然后再次回到第1课时:

SELECT * FROM x;
DELETE FROM x;
COMMIT;
第2次会议:

SELECT * FROM x;
您将看到,即使您在会话1中的
SELECT
中没有得到任何结果,您还是删除了一行。在第2课时中,您将看到最后的表格是空的。特别注意会话1的以下输出:

mysql> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM x;
Empty set (0.00 sec)

/* --- insert in session 2 happened here --- */

mysql> SELECT * FROM x;
Empty set (0.00 sec)

mysql> DELETE FROM x;
Query OK, 1 row affected (0.00 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.06 sec)

mysql> SELECT * FROM x;
Empty set (0.00 sec)
这个测试是用MySQL 5.5.12完成的

寻找正确的解决方案
  • 使用
    SERIALIZABLE
    事务隔离级别。但是请注意,会话2将阻塞
    插入
  • 似乎
    SELECT…FOR UPDATE
    也会起作用。我还没有100%深入地学习手册来理解这一点,但当我尝试它时,它起了作用。优点是您不必更改事务隔离级别。同样,会话2将阻塞
    插入
  • 分别删除
    选择后的行。基本上,您必须在
    选择中包含一个唯一的列(主键会很好),然后使用
    从x中删除,其中i在(…)
    ,或者类似的东西,其中
    中的
    包含
    选择
    结果集中的键列表。优点是您根本不需要使用事务,会话2在任何时候都不会被阻止。缺点是您有更多的数据要来回发送到SQL server。另外,我不知道单独删除行是否与使用与原始
    SELECT
    相同的
    WHERE
    子句一样有效,但是如果原始
    SELECT
    WHERE
    子句复杂或缓慢,则单独删除可能会更快,因此这可能是另一个优势

  • 编辑说,这是非常危险的事情之一,即使有文档记录,它几乎可以被认为是一个“错误”。但是,嘿,MySQL的设计者没有问我(或者其他任何人,显然)。

    你可以将行选择到一个临时表中,然后使用与选择相同的标准删除。由于SELECT FROM WHERE FOR UPDATE还返回一个结果集,因此您可以将SELECT FOR UPDATE更改为SELECT INTO tmp_表格以进行更新。然后使用原始条件或使用临时表中的数据作为条件删除选定的行

    类似这样的内容(但尚未检查语法)


    现在,您的记录已从原始表中删除,但临时表中也有一个副本,您可以保留或删除该副本。

    delete查询本身根据
    where
    子句选择行。那么您还可以期待什么呢。但是我可以在一个行结果中获得select行吗?@user157195 select语句将返回多少行?小心——这个解决方案是错误的。请参考我的答案。另外,在回答你自己的问题时,最好是
    SELECT * FROM x;
    
    mysql> SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> START TRANSACTION;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM x;
    Empty set (0.00 sec)
    
    /* --- insert in session 2 happened here --- */
    
    mysql> SELECT * FROM x;
    Empty set (0.00 sec)
    
    mysql> DELETE FROM x;
    Query OK, 1 row affected (0.00 sec)
    
    mysql> COMMIT;
    Query OK, 0 rows affected (0.06 sec)
    
    mysql> SELECT * FROM x;
    Empty set (0.00 sec)
    
    START TRANSACTION;
    SELECT a,b into TMP_TABLE FROM table_a WHERE a=1 FOR UPDATE;
    DELETE FROM table_a 
      USING table_a JOIN TMP_TABLE ON (table_a.a=TMP_TABLE.a, table_a.b=TMP_TABLE.b)
      WHERE 1=1;
    COMMIT;