【发布时间】:2016-01-28 15:36:15
【问题描述】:
我有一个 php 脚本,用于检查从安全摄像头拍摄的 2 张静止照片之间的汉明距离。
该表是具有 240 万行的 mySQL,由一个 Key 和 4 个 INT(10) 组成。 INT(10) 已单独、一起以及与 Key 一起被索引,但我没有重要证据表明任何组合都比其他组合更快。如果您建议,我可以再试一次。
汉明权重是通过将图像转换为8x16像素来计算的,每四分之一的位存储在一列中,pHash0,pHash1...等。
我有两种写法。第一种方法是使用嵌套派生表。从理论上讲,每个派生应该比它的前身有更少的数据来检查。查询是准备好的语句,而 ?字段是我正在检查的文件的 pHash[0-3]。
Select
`Key`,
Bit_Count(T3.pHash3 ^ ?) + T3.BC2 As BC3
From
(Select
*,
Bit_Count(T2.pHash2 ^ ?) + T2.BC1 As BC2
From
(Select
*,
Bit_Count(T1.pHash1 ^ ?) + T1.BC0 As BC1
From
(Select
`Key`,
pHash0,
pHash1,
pHash2,
pHash3,
Bit_Count(pHash0 ^ ?) As BC0
From
files
Where
Not pHash0 Is Null And
Bit_Count(pHash0 ^ ?) < 4) As T1
Where
Bit_Count(T1.pHash1 ^ ?) + T1.BC0 < 4) As T2
Where
Bit_Count(T2.pHash2 ^ ?) + T2.BC1 < 4) As T3
Where
Bit_Count(T3.pHash3 ^ ?) + T3.BC2 < 4
第二种方法更直接一些。它只是一次性完成所有工作。
Select
`Key`,
From
files
Where
Not pHash0 is null AND
Bit_Count(pHash0 ^ ?) + Bit_Count(pHash1 ^ ?) + Bit_Count(pHash2 ^
?) + Bit_Count(pHash3 ^ ?) < 4
第一个查询在大型记录集上更快,而第二个在较小记录集上更快,但在 240 万条记录上每次比较都不会超过 1-1/3 秒。
您是否发现了一种调整此过程以使其更快的方法?可以快速尝试任何建议,例如更改数据类型或索引。
设置为 Win7x64、MySQL/5.6.6 和 InnoDB、nginx/1.99、php-cgi/7.0.0 并启用了 zend。该脚本是从网页调用的,并且已关闭缓冲以提供即时反馈。
编辑:
如果我将 4 个 32 位整数更改为 1 个二进制 (16) 可能会更好,这会将比较从 4 更改为 1,但我还必须将我的 4 个参数转换为 128 位字符,哪个php不会做。如果有一种快速的方法可以将它们结合起来,可能会挤出更多的时间。
编辑 接受的答案将速度提高了约 500%。我们假设的简要概述:pHash "A" 的位数将始终在 pHash "B" +/- 汉明距离之内。
特别感谢@duskwuff 的坚韧和耐心。干杯@duskwuff!
编辑 这是我最近的查询:
Select
files.`Key`,
Bit_Count(? ^ pHash0) + Bit_Count(? ^ pHash1) +
Bit_Count(? ^ pHash2) + Bit_Count(? ^ pHash3) as BC
From
files FORCE INDEX (bitcount)
Where
bitCount Between ? And ?
AND Bit_Count(? ^ pHash0) + Bit_Count(? ^ pHash1) +
Bit_Count(? ^ pHash2) + Bit_Count(? ^ pHash3) <= ?
ORDER BY Bit_Count(? ^ pHash0) + Bit_Count(? ^ pHash1) +
Bit_Count(? ^ pHash2) + Bit_Count(? ^ pHash3)
前 4 个“?”代表被检查文件的 4 个 32 位哈希值,接下来的 2 个“?”表示该文件的预先计算的位数 +/- 所需的汉明距离,最后一个“?”表示汉明距离。 ORDER BY 子句仅用于将最接近的匹配项带到顶部,其中 LIMIT 1 子句将返回最佳匹配项。 bitcount 字段上有一个 B-TREE 索引。
240 万个文件的位数分布呈钟形曲线,极端为 3 或 4,中间为 70,000。如果给定一个位数为 64 的文件(这是最坏的情况),则查找汉明距离为 3 内的文件意味着比较 20% 的文件(在我的情况下为 490,000),而查找汉明距离为 0 的文件将比较只有 2.8% 的记录(当然是 70,000 条)。
【问题讨论】:
-
为什么不是简单的
BIT_COUNT(pHash0 & ?) + BIT_COUNT(pHash1 & ?) + BIT_COUNT(pHash2 & ?) + BIT_COUNT(pHash3 & ?)? -
@RickJames 是的,就像我的第二个“更直接”示例中的那样(XOR 而不是 AND)
-
糟糕,我应该说
^,而不是&。
标签: php mysql performance