使用 JOIN 永远执行更新查询

Rya*_*n M 3 mysql performance query-performance

我对数据库不是很好,所以请记住,即使解决方案听起来像每个人都已经尝试过的东西,请发布它,因为我可能还没有尝试过它,如果它有效,它将节省大量时间。

我有两个表:

  • items: ~40,000 行
  • inventory: ~1,000,000 行

我有一个的相匹配的查询inventoryitems旧系统做的方式,并更新itemidinventory表,到id匹配行的items表(工作与新系统)。

问题是查询需要永远,并且我必须运行非常相似的查询以优先考虑相似的匹配,因此等待这段时间并不是很长,因为旧数据库中的数据根本不一致,所以我必须不断地调整、重新运行、调整、重新运行等。当库存表中只有 250,000 行时,每个查询需要 40 多分钟。

简而言之,我需要使这个查询更快:

UPDATE inventory r
JOIN items t ON (FIND_IN_SET(r.orderNumber,
                REPLACE(
                    REPLACE(
                        REPLACE(t.orderNumber,'/',','),
                    ' ', ''),
                '[]',',')
            )
            AND r.selected_number != '99999'
            AND r.guideid = t.guideid
            AND (r.itemid IS NULL OR r.itemid = '')
                 )
SET r.itemid = t.id
Run Code Online (Sandbox Code Playgroud)

我的索引是(逗号分隔显然是复合的,请原谅它们由 SQLYog 自动生成的名称):

items 桌子:

PRIMARY => `id`
guideid => `guideid`, `orderNumber`
guideid_2 => `guideid`
orderNumber => `orderNumber`
Run Code Online (Sandbox Code Playgroud)

inventory 桌子:

PRIMARY => `id`
guideid => `guideid`, `orderNumber`
temp_usNum => `temp_usNum`
orderNumber => `orderNumber`
selected_number => `selected_number`
guideid_2 => `guideid`
itemid => `itemid`
itemid_2 => `itemid`, `guideid`, `orderNumber`, `selected_number`
Run Code Online (Sandbox Code Playgroud)

这是解释查询的结果:

解释输出

我可以访问所有服务器设置,就像在我的本地机器上一样。

jyn*_*nus 7

使用您当前的结构,您的查询可能会进行 >1,000,000,000 次行扫描。这可能是由于FIND_IN_SET- 意味着该列不能在索引中使用,导致优化器选择其他索引的选择性非常差(您必须读取 500000 行而不是 100 万行,这是非常糟糕的选择性)。正在使用索引的事实并不意味着良好的性能,如果它是错误的索引。要理解为什么,您必须知道function(column) = value在 MySQL 中不能直接索引。

我将首先更改列items.ordernumber并将该信息放在一个单独的表中,每列只有一个项目,而不是您当前拥有的非规范化安排。

有了它,以及适当的索引,您将能够在项目 -> 库存方向中进行查询,并用于ordernumber充分过滤您的行。

其次,您有许多冗余索引,例如 (guideid, orderNumber) 和 (guideid)。您需要在设计方面进行良好的清理。

要测量您为特定查询执行的行操作数,请执行以下操作:

FLUSH STATUS;
-- Execute query
SHOW STATUS like 'Hand%';
Run Code Online (Sandbox Code Playgroud)