加快 SQL 大型 table 查询的方法
Ways to speed up SQL query on large table
我有一个 MySQL table 1000 万行和 3 列,格式如下:
id time num
ca65e871-d758-437e-b76f-175234760e7b 2020-11-14T23:08:05.553770Z 11112222222
...
我正在尝试计算特定数量和所需时间范围内的出现次数,如下所示:
"SELECT COUNT(*) FROM TABLE_NAME WHERE time >'2020-11-14T23:08:05.553752Z' and num = '11112222222'"
我是来自 Python 环境 (python 3.x) 的 运行 查询,它使用 pymysql
包连接到 MySQL 数据库。在 10MM 行上,此执行持续约 2.8 秒。在 time
和 num
列上添加索引后,执行速度几乎快了一倍:1.5 秒.
我的问题是我可以进一步加快速度吗?
理想情况下,执行时间应该在 200 毫秒以下,所以我不知道这是否可能。提前致谢!
对于此查询:
SELECT COUNT(*)
FROM TABLE_NAME
WHERE time > '2020-11-14T23:08:05.553752Z' AND num = '11112222222'
您想要 (num, time)
上的多列索引。索引中列的顺序很重要。您希望首先具有相等谓词的列,然后是具有不等谓词的列。
我对数据类型有点怀疑。如果 num
是数字数据类型(看起来像 int
),那么您应该根据文字数字过滤它:
num = 11112222222
进一步加快查询速度的唯一方法是缩小数据类型。
num = '11112222222'
不需要更改,但是...
BIGINT
是 8 个字节。如果你能忍受 40 亿的限制,请使用 INT UNSIGNED
(4 个字节)。
不幸的是,MySQL 无法将字符串 '2020-11-14T23:08:05.553770Z'
理解为 DATETIME
(也不是 TIMESTAMP
) 如果 time
是 VARCHAR(27),然后一切正常。但是如果你可以切换到兼容的格式,很多 space 将被保存为 DATETIME(6)
,它只有 8 个字节(而 varchar 为 28 个字节)。
UUIDs
由于其随机性,体积庞大且效率低下。您可能正在使用 CHAR(36) CHARACTER SET ascii
—— 36 字节。将其打包(参见 MySQL 8.0)为 `BINARY(16) -- 16 字节。
这些会显着缩小 table 和索引,从而提高性能。
对于 UUID 的转换代码:http://mysql.rjweb.org/doc.php/uuid#code_to_do_it 另外 MySQL 8.0 也有一对类似的内置函数。
此外,T
和 Z
不是 DATETIME(6)
的有效字符,因此需要进行一些编辑。
我有一个 MySQL table 1000 万行和 3 列,格式如下:
id time num
ca65e871-d758-437e-b76f-175234760e7b 2020-11-14T23:08:05.553770Z 11112222222
...
我正在尝试计算特定数量和所需时间范围内的出现次数,如下所示:
"SELECT COUNT(*) FROM TABLE_NAME WHERE time >'2020-11-14T23:08:05.553752Z' and num = '11112222222'"
我是来自 Python 环境 (python 3.x) 的 运行 查询,它使用 pymysql
包连接到 MySQL 数据库。在 10MM 行上,此执行持续约 2.8 秒。在 time
和 num
列上添加索引后,执行速度几乎快了一倍:1.5 秒.
我的问题是我可以进一步加快速度吗?
理想情况下,执行时间应该在 200 毫秒以下,所以我不知道这是否可能。提前致谢!
对于此查询:
SELECT COUNT(*)
FROM TABLE_NAME
WHERE time > '2020-11-14T23:08:05.553752Z' AND num = '11112222222'
您想要 (num, time)
上的多列索引。索引中列的顺序很重要。您希望首先具有相等谓词的列,然后是具有不等谓词的列。
我对数据类型有点怀疑。如果 num
是数字数据类型(看起来像 int
),那么您应该根据文字数字过滤它:
num = 11112222222
进一步加快查询速度的唯一方法是缩小数据类型。
num = '11112222222'
不需要更改,但是...
BIGINT
是 8 个字节。如果你能忍受 40 亿的限制,请使用 INT UNSIGNED
(4 个字节)。
不幸的是,MySQL 无法将字符串 '2020-11-14T23:08:05.553770Z'
理解为 DATETIME
(也不是 TIMESTAMP
) 如果 time
是 VARCHAR(27),然后一切正常。但是如果你可以切换到兼容的格式,很多 space 将被保存为 DATETIME(6)
,它只有 8 个字节(而 varchar 为 28 个字节)。
UUIDs
由于其随机性,体积庞大且效率低下。您可能正在使用 CHAR(36) CHARACTER SET ascii
—— 36 字节。将其打包(参见 MySQL 8.0)为 `BINARY(16) -- 16 字节。
这些会显着缩小 table 和索引,从而提高性能。
对于 UUID 的转换代码:http://mysql.rjweb.org/doc.php/uuid#code_to_do_it 另外 MySQL 8.0 也有一对类似的内置函数。
此外,T
和 Z
不是 DATETIME(6)
的有效字符,因此需要进行一些编辑。