我怎样才能使 "euclidean distance calculation" 在 MySQL 中更快?
How can I make "euclidean distance calculation" faster in MySQL?
我正在创建人脸识别系统,但搜索速度很慢。能否分享一下如何加快搜索速度?
100,000个数据项大约需要6秒。
- MySQL
mysql> SHOW VARIABLES LIKE '%version%';
+--------------------------+------------------------------+
| Variable_name | Value |
+--------------------------+------------------------------+
| version | 8.0.29 |
| version_comment | MySQL Community Server - GPL |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
+--------------------------+------------------------------+
- Table
CREATE TABLE `face_feature` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`f1` decimal(9,8) NOT NULL,
`f2` decimal(9,8) NOT NULL,
...
...
`f127` decimal(9,8) NOT NULL,
`f128` decimal(9,8) NOT NULL,
PRIMARY KEY (id)
);
- 数据
mysql> SELECT count(*) FROM face_feature;
+----------+
| count(*) |
+----------+
| 110004 |
+----------+
mysql> SELECT * FROM face_feature LIMIT 1\G;
id: 1
f1: -0.07603023
f2: 0.13605964
...
f127: 0.09608927
f128: 0.00082345
- SQL
SELECT
id,
sqrt(
power(f1 - (-0.09077361), 2) +
power(f2 - (0.10373443), 2) +
...
...
power(f127 - (0.0778369), 2) +
power(f128 - (0.00951046), 2)
) as distance
FROM
face_feature
ORDER BY
distance
LIMIT
1
;
- 结果
+----+--------------------+
| id | distance |
+----+--------------------+
| 1 | 0.3376853491771237 |
+----+--------------------+
1 row in set (6.18 sec)
更新 1:
已从 decimal(9,8)
更改为 float(9,8)
然后,从approximately 4sec
提高到3.26 sec
mysql> desc face_feature;
+-------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| f1 | float(9,8) | NO | | NULL | |
| f2 | float(9,8) | NO | | NULL | |
..
| f127 | float(9,8) | NO | | NULL | |
| f128 | float(9,8) | NO | | NULL | |
+-------+------------+------+-----+---------+----------------+
更新 2:
已从 POWER(z, 2)
更改为 z*z
然后,结果由3.26 sec
改为4.65 sec
SELECT
id,
sqrt(
((f1 - (-0.09077361)) * (f1 - (-0.09077361))) +
((f2 - (0.10373443)) * (f2 - (0.10373443))) +
((f3 - (0.00798536)) * (f3 - (0.00798536))) +
...
...
((f126 - (0.07803915)) * (f126 - (0.07803915))) +
((f127 - (0.0778369)) * (f127 - (0.0778369))) +
((f128 - (0.00951046)) * (f128 - (0.00951046))
) as distance
FROM
face_feature
ORDER BY
distance
LIMIT
1
;
更新 3
我正在研究 MySQL GIS 的用法。
更新 4
我也在看 PostgreSQL,因为我找不到在 MySQL.
中处理 128 个维度的方法
DECIMAL(9,8)
-- 这是很多有效数字。需要那么精确吗?
FLOAT
-- 约7位有效数字;更快的算法。
POWER(z, 2)
-- 可能比 z*z
慢很多。 (这可能是最慢的部分。)
SQRT
-- 在很多情况下,您可以简单地使用正方形。在这种情况下:
SELECT SQRT(closest)
FROM ( SELECT -- leave out SQRT
... ORDER BY .. LIMIT 1 )
这里有一些其他的想法。它们不一定与正在讨论的查询相关:
精确测试 -- 小心比较 'equal' 舍入误差很可能使事情出乎意料地不相等。不精确的测量增加了这个问题。如果我测量两次,我可能会得到一次 1.23456789 和下一次 1.23456788。 (特别是在那种“精度”水平上。
Trade complexity vs speed -- 使用ABS(a - b)
作为距离公式;以这种方式找到最接近的 10 个项目,然后使用欧几里德距离获得 'right' 距离。
把脸分成几个区域。查找项目所在的区域,然后仅检查该区域中 128 个点的子集。 (靠近边界 -- 在两个区域中放置一些点。)
跳出框框思考 -- 我不熟悉你的面部识别,所以我 运行 没有数学技巧。
切换到 POINTs
和 SPATIAL
索引。您的任务可能会快几个数量级。 (这对于 128 维 space 可能不实用。)
我正在创建人脸识别系统,但搜索速度很慢。能否分享一下如何加快搜索速度?
100,000个数据项大约需要6秒。
- MySQL
mysql> SHOW VARIABLES LIKE '%version%';
+--------------------------+------------------------------+
| Variable_name | Value |
+--------------------------+------------------------------+
| version | 8.0.29 |
| version_comment | MySQL Community Server - GPL |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
+--------------------------+------------------------------+
- Table
CREATE TABLE `face_feature` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`f1` decimal(9,8) NOT NULL,
`f2` decimal(9,8) NOT NULL,
...
...
`f127` decimal(9,8) NOT NULL,
`f128` decimal(9,8) NOT NULL,
PRIMARY KEY (id)
);
- 数据
mysql> SELECT count(*) FROM face_feature;
+----------+
| count(*) |
+----------+
| 110004 |
+----------+
mysql> SELECT * FROM face_feature LIMIT 1\G;
id: 1
f1: -0.07603023
f2: 0.13605964
...
f127: 0.09608927
f128: 0.00082345
- SQL
SELECT
id,
sqrt(
power(f1 - (-0.09077361), 2) +
power(f2 - (0.10373443), 2) +
...
...
power(f127 - (0.0778369), 2) +
power(f128 - (0.00951046), 2)
) as distance
FROM
face_feature
ORDER BY
distance
LIMIT
1
;
- 结果
+----+--------------------+
| id | distance |
+----+--------------------+
| 1 | 0.3376853491771237 |
+----+--------------------+
1 row in set (6.18 sec)
更新 1:
已从 decimal(9,8)
更改为 float(9,8)
然后,从approximately 4sec
提高到3.26 sec
mysql> desc face_feature;
+-------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| f1 | float(9,8) | NO | | NULL | |
| f2 | float(9,8) | NO | | NULL | |
..
| f127 | float(9,8) | NO | | NULL | |
| f128 | float(9,8) | NO | | NULL | |
+-------+------------+------+-----+---------+----------------+
更新 2:
已从 POWER(z, 2)
更改为 z*z
然后,结果由3.26 sec
改为4.65 sec
SELECT
id,
sqrt(
((f1 - (-0.09077361)) * (f1 - (-0.09077361))) +
((f2 - (0.10373443)) * (f2 - (0.10373443))) +
((f3 - (0.00798536)) * (f3 - (0.00798536))) +
...
...
((f126 - (0.07803915)) * (f126 - (0.07803915))) +
((f127 - (0.0778369)) * (f127 - (0.0778369))) +
((f128 - (0.00951046)) * (f128 - (0.00951046))
) as distance
FROM
face_feature
ORDER BY
distance
LIMIT
1
;
更新 3
我正在研究 MySQL GIS 的用法。
更新 4
我也在看 PostgreSQL,因为我找不到在 MySQL.
中处理 128 个维度的方法DECIMAL(9,8)
-- 这是很多有效数字。需要那么精确吗?FLOAT
-- 约7位有效数字;更快的算法。POWER(z, 2)
-- 可能比z*z
慢很多。 (这可能是最慢的部分。)SQRT
-- 在很多情况下,您可以简单地使用正方形。在这种情况下:SELECT SQRT(closest) FROM ( SELECT -- leave out SQRT ... ORDER BY .. LIMIT 1 )
这里有一些其他的想法。它们不一定与正在讨论的查询相关:
精确测试 -- 小心比较 'equal' 舍入误差很可能使事情出乎意料地不相等。不精确的测量增加了这个问题。如果我测量两次,我可能会得到一次 1.23456789 和下一次 1.23456788。 (特别是在那种“精度”水平上。
Trade complexity vs speed -- 使用
ABS(a - b)
作为距离公式;以这种方式找到最接近的 10 个项目,然后使用欧几里德距离获得 'right' 距离。把脸分成几个区域。查找项目所在的区域,然后仅检查该区域中 128 个点的子集。 (靠近边界 -- 在两个区域中放置一些点。)
跳出框框思考 -- 我不熟悉你的面部识别,所以我 运行 没有数学技巧。
切换到
POINTs
和SPATIAL
索引。您的任务可能会快几个数量级。 (这对于 128 维 space 可能不实用。)