mysql - 如何提高 200 多万条记录的查询性能

标签 mysql sql database-performance temp-tables

背景

我有一个 MySQL 测试环境,其中包含一个包含超过 2 亿行的表。在此表上必须执行两种类型的查询;

  1. 某些行是否存在。 给定一个 client_id 和一个 sgtin 列表,最多可以容纳 50.000 项,我需要知道表中存在哪些 sgtin
  2. 选择那些行。 给定一个 client_id 和一个 sgtin 列表,最多可以容纳 50.000 个项目,我需要获取整行。 (商店,GTIN ...)

对于单个“client_id”,该表可以增长到 2 亿多条记录。

测试环境

至强 E3-1545M/32GB 内存/固态硬盘。 InnoDB 缓冲池 24GB。 (生产将是具有 192GB RAM 的更大服务器)

表格

CREATE TABLE `sgtins` (
  `client_id` INT UNSIGNED NOT NULL,
  `sgtin` varchar(255) NOT NULL,
  `store` varchar(255) NOT NULL,
  `gtin` varchar(255) NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX (`client_id`, `store`, `sgtin`),
  INDEX (`client_id`),
  PRIMARY KEY (`client_id`,`sgtin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

测试

首先,我生成了分布在 10 个“client_id”上的随机 sgtin 值,以用 2 亿行填充表。

我创建了一个基准工具来执行我尝试过的各种查询。我还使用解释计划找出最佳性能。对于每次测试,该工具将从我用来填充数据库的数据中读取新的随机数据。确保每个查询都是不同的。

对于这篇文章,我将使用 28 个 sgtin临时表

CREATE TEMPORARY TABLE sgtins_tmp_table (`sgtin` varchar(255) primary key)
 engine=MEMORY;

存在查询

我使用此查询来查明 sgtin 是否存在。这也是我发现的最快的查询。对于 50K sgtin,此查询将花费 3 到 9 秒。

-- cost = 17 for 28 sgtins loaded in the temp table.
SELECT sgtin
FROM sgtins_tmp_table
WHERE EXISTS 
  (SELECT sgtin FROM sgtins 
  WHERE sgtins.client_id = 4 
  AND sgtins.sgtin = sgtins_tmp_table.sgtin);

Explain plan

选择查询

-- cost = 50.60 for 28 sgtins loaded in the temp table. 50K not usable.
SELECT sgtins.sgtin, sgtins.store, sgtins.timestamp
FROM sgtins_tmp_table, sgtins
WHERE sgtins.client_id = 4
AND sgtins_tmp_table.sgtin = sgtins.sgtin;

Explain plan

-- cost = 64 for 28 sgtins loaded in the temp table.
SELECT sgtins.sgtin, sgtins.store, sgtins.timestamp
FROM sgtins
WHERE sgtins.client_id = 4
AND sgtins.sgtin IN ( SELECT sgtins_tmp_table.sgtin
 FROM sgtins_tmp_table);

Explain plan

-- cost = 50.60 for 28 sgtins loaded in the temp table.
SELECT sgtins_tmp_table.epc, sgtins.store
FROM sgtins_tmp_table, sgtins
WHERE exists (SELECT organization_id, sgtin FROM sgtins WHERE client_id = 4 AND sgtins.sgtin = sgtins_tmp_table.sgtin)
AND sgtins.client_id = 4
AND sgtins_tmp_table.sgtin = sgtins.sgtin;

Explain plan

总结

exist 查询可用,但选择速度很慢。我该怎么办?欢迎任何建议:)

最佳答案

我会这样写你的 exists 查询:

SELECT stt.sgtin
FROM sgtins_tmp_table stt
WHERE EXISTS (SELECT 1
              FROM sgtins s
              WHERE s.client_id = 4 AND
                    s.sgtin = stt.sgtin
             );

对于此查询,您需要在 sgtins(sgtin, client_id) 上建立索引。

关于mysql - 如何提高 200 多万条记录的查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56576289/

相关文章:

sql - 如何估计 SQL Server 表中插入的单行的理论大小

android - 在 Android 中使用 SQLite 数据库实现队列

Oracle 首选列长度

php - 如果我的应用程序的许多 Laravel 4 查询需要是 DB::raw,那么使用 Eloquent 有什么优势?

PHP/MySQL OnClick 更新 MySQL

mysql - bash 从命令行使用 mysql 中的变量

多边形内的SQL Geography点在ST​​Intersect上不返回true(但使用Geometry返回true)

MySQL 到 Excel VBA

php - 如何使用mysql数据库根据条件更新多行?

sql - Extbase - 从查询中获取创建的 sql