加快大表SQL查询的方法
Posted
技术标签:
【中文标题】加快大表SQL查询的方法【英文标题】:Ways to speed up SQL query on large table 【发布时间】:2020-11-18 10:51:35 【问题描述】:我有一个 1000 万行和 3 列的 mysql 表,格式如下:
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 毫秒,所以我不知道这是否可能。提前谢谢!
【问题讨论】:
请更具体地说明您的起点,例如概述不同的层以及它们如何影响您的查询持续时间。您应该跟踪不同的调用并检查它是查询执行、网络传输还是 Python-/pymysql-overhead。至少分片和并行查询总是有效,但会增加复杂性。 【参考方案1】:对于这个查询:
SELECT COUNT(*)
FROM TABLE_NAME
WHERE time > '2020-11-14T23:08:05.553752Z' AND num = '11112222222'
您希望在(num, time)
上建立一个多列索引。索引中列的顺序很重要。您首先需要具有等式谓词的列,然后是具有不等式谓词的列。
我对数据类型有点怀疑。如果num
是数字数据类型(看起来像int
),那么您应该根据文字数字对其进行过滤:
num = 11112222222
【讨论】:
非常感谢。我在(num, time)
上添加了一个索引,现在执行时间不到 5 毫秒。惊人的建议,再次感谢!顺便说一句,num
是bigint
类型,并且更改过滤(针对您所说的文字数字)并没有太大帮助。你认为也许我应该把num
列转成varchar
吗?这是否有助于进一步加快查询速度?
在这种情况下,'123'
在开始查询之前会变成123
。因此,您不会看到明显的速度差异。相反的是程序员被搞砸的地方:varchar_col = 123
转换列,而不是123
。也就是说,就您而言;将num
保留为BIGINT
,不要担心文字。【参考方案2】:
进一步加快查询速度的唯一方法是缩小数据类型。
num = '11112222222'
不需要更改,但是...
BIGINT
是 8 个字节。如果您可以忍受 40 亿的限制,请使用 INT UNSIGNED
(4 个字节)。
不幸的是,MySQL 不将字符串 '2020-11-14T23:08:05.553770Z'
理解为 DATETIME
(也不理解 TIMESTAMP
)如果 time
是 VARCHAR(27),那么一切正常。但是如果你可以切换到兼容的格式,DATETIME(6)
会节省很多空间,它只有 8 个字节(而 varchar 是 28 个字节)。
UUIDs
体积庞大且效率低下,因为它们具有随机性。您可能正在使用 CHAR(36) CHARACTER SET ascii
-- 36 字节。将它(参见 MySQL 8.0)打包成 `BINARY(16) -- 16 字节。
这些会显着缩小表和索引,从而提高性能。
对于 UUID 的转换代码:http://mysql.rjweb.org/doc.php/uuid#code_to_do_it MySQL 8.0 也有一对类似的内置函数。
另外,T
和 Z
不是 DATETIME(6)
的有效字符,因此需要进行一些编辑。
【讨论】:
谢谢!我将使用datetime(6)
和UUID
在数据包binary
表单中。关于后者,我认为这是一个好方法吗? mysqltutorial.org/mysql-uuid
@Makaroni - 我添加了几段。以上是关于加快大表SQL查询的方法的主要内容,如果未能解决你的问题,请参考以下文章