MySql:使用长组合 PK 列表对多行进行操作

发布于 2024-08-21 09:42:38 字数 1684 浏览 9 评论 0原文

考虑到我在与 ODBC 连接的客户端应用程序中有一长串键,那么在 MySql 中处理多行的好方法是什么?

注意:我的经验主要是 SQL Server,所以我了解一点,但不是专门了解 MySQL。

任务是从 9 个表中删除一些行,但我可能有超过 5,000 个密钥对。

我从简单的方法开始,循环遍历所有键并针对每个表为每个键提交一条语句,例如:

DELETE FROM Table WHERE Key1 = 123 AND Key2 = 567 -- and 8 more tables
DELETE FROM Table WHERE Key1 = 124 AND Key2 = 568 -- and 8 more tables
DELETE FROM Table WHERE Key1 = 125 AND Key2 = 569 -- and 8 more tables
...

除了,这会产生 45,000 个单独的语句,您可以想象这有点慢。

那么,不用担心我在前端使用的编程语言,有什么好方法可以提交列表,以便我可以加入并立即或至少批量执行操作?到目前为止,我的想法如下:

  • 创建一个临时表并插入其中,然后加入。我很乐意查找 MySQL 的语法来创建临时表,但是这是一个好的方法吗?

  • 假设我确实使用临时表,填充临时表的最佳方法是什么? 5000 个 INSERT Table VALUES () 语句? 选择 123, 456 联合所有选择 124, 457?我刚刚测试了 MySql 允许这种不针对表发出的 SELECT。但是如果列表太长,SQL Server 最终会崩溃,那么这在 MySQL 中是一个好方法吗?我应该一次将列表保持在几百个吗?

    --CREATE Temp Table(我还不知道MySql中的语法)
    
    插入临时表
    选择 123, 456
    联合所有选择 124, 457
    联合所有选择 125, 458
    
    删除T
    从
       药片
       INNER JOIN TempTable X ON T.Key1 = X.Key1 AND T.Key2 = X.Key2
    
  • XML。我发现 MySQL 5.1 有一些 XML 函数,但从粗略搜索来看,它似乎不支持将 XML 文本块转换为行集以进行连接。这是真的吗?对我来说,将值转换为 XML 非常容易。

  • 虚拟分割操作。我认为在 MySql 中可能存在某种过程语言。在 SQL Server 中,我可以编写一些自定义代码来解析字符串并将其转换为行集:

    创建过程 DoStuff @KeyString varchar(max)
    作为
    声明 @Keys 表 (
       键 1 整数,
       键2整数,
       主键聚集(Key1、Key2)
    )
    声明@Pos int
    而@Pos < Len(@KeyString) 开始
       -- 循环搜索@KeyString 中的分隔逗号
       -- 并将已解析的标记对插入表变量@Keys
    结尾
    
    删除T
    从
       药片
       内连接 @Keys K ON T.Key1 = K.Key1 AND T.Key2 = K.Key2
    

由于我不熟悉 MySQL,我真的不知道首先要调查哪种可能性,并且我希望得到一些帮助来帮助我做出错误的决定和/或以艰难的方式学习。

What's a good way to work with many rows in MySql, given that I have a long list of keys in a client application that is connecting with ODBC?

Note: my experience is largely SQL Server, so I know a bit, just not MySQL specifically.

The task is to delete some rows from 9 tables, but I might have upwards of 5,000 key pairs.

I started out with the easy way of looping through all my keys and submitting a statement for each one against each table, such as:

DELETE FROM Table WHERE Key1 = 123 AND Key2 = 567 -- and 8 more tables
DELETE FROM Table WHERE Key1 = 124 AND Key2 = 568 -- and 8 more tables
DELETE FROM Table WHERE Key1 = 125 AND Key2 = 569 -- and 8 more tables
...

Except, that comes out to 45,000 separate statements, which as you can imagine is a bit slow.

So, without worrying about the programming language I'm using on the front end, what's a good way to submit the list so that I can JOIN and do the operation all at once or at least in large batches? Here are my ideas so far:

  • Create a temp table and insert to it, then join. I'll happily look up the syntax for MySQL to create a temp table, but is that a good route to go?

  • Assuming I do use a temp table, what's the best method for populating a temp table? 5000 INSERT Table VALUES () statements? SELECT 123, 456 UNION ALL SELECT 124, 457? I just tested that MySql allows this kind of SELECT that is not issued against a table. But SQL Server eventually blows up if the list gets too long, so is this a good way in MySQL? Should I just keep the list to a few hundred at once?

    --CREATE Temp Table ( I do not know the syntax in MySql yet)
    
    INSERT INTO TempTable
    SELECT 123, 456
    UNION ALL SELECT 124, 457
    UNION ALL SELECT 125, 458
    
    DELETE T
    FROM
       Table T
       INNER JOIN TempTable X ON T.Key1 = X.Key1 AND T.Key2 = X.Key2
    
  • XML. I see MySQL 5.1 has some XML functions, but from a cursory search it doesn't appear to support turning a chunk of XML text into a rowset to join against. Is that true? It is extremely easy for me to get the values into XML.

  • A virtual split operation. I presume in MySql that there's some kind of procedural language possible. In SQL Server I could write some custom code that parses a string and turns it into a rowset:

    CREATE PROCEDURE DoStuff @KeyString varchar(max)
    AS
    DECLARE @Keys TABLE (
       Key1 int,
       Key2 int,
       PRIMARY KEY CLUSTERED (Key1, Key2)
    )
    DECLARE @Pos int
    WHILE @Pos < Len(@KeyString) BEGIN
       -- loop to search for delimiting commas in @KeyString
       -- and insert pairs of parsed tokens to table variable @Keys
    END
    
    DELETE T
    FROM
       Table T
       INNER JOIN @Keys K ON T.Key1 = K.Key1 AND T.Key2 = K.Key2
    

Since I'm unfamiliar with MySQL, I really don't know which possibility to investigate first, and I would appreciate some help to save me from making a poor decision and/or learning the hard way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

别念他 2024-08-28 09:42:38

我将使用临时表解决方案,并将其连接到 DELETE 语句中的每个主表。因此,您只需执行九次删除,每个表一次。


回复您的评论:

CREATE TABLE 上的 MySQL 文档说明如下:

临时表仅对当前连接可见,并在连接关闭时自动删除。这意味着两个不同的连接可以使用相同的临时表名称,而不会相互冲突或与现有的同名非 TEMPORARY 表发生冲突。 (现有表将被隐藏,直到临时表被删除。)

这非常清楚!

关于加载数据,您可以使用 INSERT 来完成。 5000 行没什么大不了的。我使用 PHP 脚本将数百万行(例如 StackOverflow XML 数据转储)加载到 MySQL 中,这只需要大约 20 分钟。我使用准备好的语句,然后使用参数执行它。

I would use the temp table solution, and join it to each main table in the DELETE statements. So you only have to do nine deletes, one for each table.

  • CREATE TEMPORARY TABLE

    CREATE TEMPORARY TABLE Keys (
        Key1 INT UNSIGNED NOT NULL, 
        Key2 INT UNSIGNED NOT NULL, 
        PRIMARY KEY(Key1, Key2)
    );
    
  • Load a file of tab-separated data into the temp table using LOAD DATA LOCAL INFILE

    LOAD DATA LOCAL INFILE 'C:/path/to/datafile' INTO TABLE Keys;
    
  • Delete using MySQL's multi-table DELETE syntax.

    DELETE t FROM Table1 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table2 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table3 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table4 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table5 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table6 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table7 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table8 t JOIN Keys USING (Key1, Key2);
    DELETE t FROM Table9 t JOIN Keys USING (Key1, Key2);
    

Re your comment:

The MySQL docs on CREATE TABLE say the following:

A TEMPORARY table is visible only to the current connection, and is dropped automatically when the connection is closed. This means that two different connections can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name. (The existing table is hidden until the temporary table is dropped.)

That's pretty clear!

Regarding loading the data, you could just do it with INSERT. 5000 rows is no big deal. I use a PHP script to load millions of rows (e.g. the StackOverflow XML data dump) into MySQL and that only takes about 20 minutes. I use a prepared statement and then execute it with parameters.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文