MySQL:优化查询以从字符串集中查找匹配的字符串
MySQL: Optimized query to find matching strings from set of strings
我有 10 组弦,每组有 9 根弦。在这 10 组中,第一组中的所有字符串的长度为 10,第二组中的所有字符串的长度为 9,依此类推。最后,第 10 组中的所有字符串的长度均为 1。
每组有(length-2)个字符的公共前缀。并且在下一组中前缀长度减少 1。因此,第一组共有 8 个字符,第二组有 7 个,依此类推。
这是 10 组样本的样子:
pu3q0k0vwn
pu3q0k0vwp
pu3q0k0vwr
pu3q0k0vwq
pu3q0k0vwm
pu3q0k0vwj
pu3q0k0vtv
pu3q0k0vty
pu3q0k0vtz
pu3q0k0vw
pu3q0k0vy
pu3q0k0vz
pu3q0k0vx
pu3q0k0vr
pu3q0k0vq
pu3q0k0vm
pu3q0k0vt
pu3q0k0vv
pu3q0k0v
pu3q0k0y
pu3q0k1n
pu3q0k1j
pu3q0k1h
pu3q0k0u
pu3q0k0s
pu3q0k0t
pu3q0k0w
pu3q0k0
pu3q0k2
pu3q0k3
pu3q0k1
pu3q07c
pu3q07b
pu3q05z
pu3q0hp
pu3q0hr
pu3q0k
pu3q0m
pu3q0t
pu3q0s
pu3q0e
pu3q07
pu3q05
pu3q0h
pu3q0j
pu3q0
pu3q2
pu3q3
pu3q1
pu3mc
pu3mb
pu3jz
pu3np
pu3nr
pu3q
pu3r
pu3x
pu3w
pu3t
pu3m
pu3j
pu3n
pu3p
pu3
pu9
pud
pu6
pu4
pu1
pu0
pu2
pu8
pu
pv
0j
0h
05
pg
pe
ps
pt
p
r
2
0
b
z
y
n
q
要求:
我有一个 table PROFILES,其中包含列 SRNO(类型 bigint,主键)和 UNIQUESTRING(类型 char(10),唯一键)。我想从这 10 组中找到 450 个 SRNO 来匹配 UNIQUESTRING。
首先在第一组中找到字符串like。如果我们没有得到足够的结果(即 450),请在第二组中查找字符串 like。如果我们仍然没有得到足够的结果(450 减去 第一组的结果 ),在第三组中查找字符串 like。等等。
现有解决方案:
我写了类似这样的查询:
select srno from profiles
where ( (uniquestring like 'pu3q0k0vwn%')
or (uniquestring like 'pu3q0k0vwp%') -- all those above uniquestrings after this and finally the last one
or (uniquestring like 'n%')
or (uniquestring like 'q%')
)
limit 450
但是,在收到 Rick James 在此 中的反馈后,我意识到这不是优化的查询,因为它涉及的行比它需要的多。
所以我打算像这样重写查询:
(select srno from profiles where uniquestring like 'pu3q0k0vwn%' LIMIT 450)
UNION DISTINCT
(select srno from profiles where uniquestring like 'pu3q0k0vwp%' LIMIT 450); -- and more such clauses after this for each uniquestring
我想知道是否有更好的解决方案。
SELECT ...
WHERE str LIKE 'pu3q0k0vw%' AND -- the 10-char set
str REGEXP '^pu3q0k0vw[nprqmj]' -- the 9 next letters
LIMIT ...
# then check for 450; if not enough, continue...
SELECT ...
WHERE str LIKE 'pu3q0k0vt%' AND -- the 10-char set
str REGEXP '^pu3q0k0vt[vyz]' -- the 9 next letters
LIMIT 450
# then check for 450; if not enough, continue...
etc.
SELECT ...
WHERE str LIKE 'pu3q0k0v%' AND -- the 9-char set
str REGEXP '^pu3q0k0v[wyzxrqmtv]' -- the 9 next letters
LIMIT ...
# check, etc; for a total of 10 SELECTs or 450 rows, whichever comes first.
这将是 10+ select 秒。每个 select 将通过首先选择具有 LIKE 公共前缀的行进行某种程度的优化,然后使用 REGEXP 进行双重检查。
(如果您不喜欢将不一致的 pu3q0k0vw
与 pu3q0k0vt
分开;我们可以进一步讨论。)
你说"prefix";我已经对 LIKE 和 REGEXP 进行了编码,以假定任意文本 在 给定的前缀之后。
UNION
不可行,因为它(我认为)会在选择 450 之前收集所有行。每个 SELECT
将停在 LIMIT
if 没有 DISTINCT
GROUP BY
或 ORDER BY
需要先收集所有东西。
REGEXP
不够智能,无法避免扫描整个 table;添加 LIKE
可以避免这种情况(除非有超过 20% 的行与 LIKE
匹配)。
我有 10 组弦,每组有 9 根弦。在这 10 组中,第一组中的所有字符串的长度为 10,第二组中的所有字符串的长度为 9,依此类推。最后,第 10 组中的所有字符串的长度均为 1。
每组有(length-2)个字符的公共前缀。并且在下一组中前缀长度减少 1。因此,第一组共有 8 个字符,第二组有 7 个,依此类推。
这是 10 组样本的样子:
pu3q0k0vwn
pu3q0k0vwp
pu3q0k0vwr
pu3q0k0vwq
pu3q0k0vwm
pu3q0k0vwj
pu3q0k0vtv
pu3q0k0vty
pu3q0k0vtz
pu3q0k0vw
pu3q0k0vy
pu3q0k0vz
pu3q0k0vx
pu3q0k0vr
pu3q0k0vq
pu3q0k0vm
pu3q0k0vt
pu3q0k0vv
pu3q0k0v
pu3q0k0y
pu3q0k1n
pu3q0k1j
pu3q0k1h
pu3q0k0u
pu3q0k0s
pu3q0k0t
pu3q0k0w
pu3q0k0
pu3q0k2
pu3q0k3
pu3q0k1
pu3q07c
pu3q07b
pu3q05z
pu3q0hp
pu3q0hr
pu3q0k
pu3q0m
pu3q0t
pu3q0s
pu3q0e
pu3q07
pu3q05
pu3q0h
pu3q0j
pu3q0
pu3q2
pu3q3
pu3q1
pu3mc
pu3mb
pu3jz
pu3np
pu3nr
pu3q
pu3r
pu3x
pu3w
pu3t
pu3m
pu3j
pu3n
pu3p
pu3
pu9
pud
pu6
pu4
pu1
pu0
pu2
pu8
pu
pv
0j
0h
05
pg
pe
ps
pt
p
r
2
0
b
z
y
n
q
要求: 我有一个 table PROFILES,其中包含列 SRNO(类型 bigint,主键)和 UNIQUESTRING(类型 char(10),唯一键)。我想从这 10 组中找到 450 个 SRNO 来匹配 UNIQUESTRING。
首先在第一组中找到字符串like。如果我们没有得到足够的结果(即 450),请在第二组中查找字符串 like。如果我们仍然没有得到足够的结果(450 减去 第一组的结果 ),在第三组中查找字符串 like。等等。
现有解决方案: 我写了类似这样的查询:
select srno from profiles
where ( (uniquestring like 'pu3q0k0vwn%')
or (uniquestring like 'pu3q0k0vwp%') -- all those above uniquestrings after this and finally the last one
or (uniquestring like 'n%')
or (uniquestring like 'q%')
)
limit 450
但是,在收到 Rick James 在此
(select srno from profiles where uniquestring like 'pu3q0k0vwn%' LIMIT 450)
UNION DISTINCT
(select srno from profiles where uniquestring like 'pu3q0k0vwp%' LIMIT 450); -- and more such clauses after this for each uniquestring
我想知道是否有更好的解决方案。
SELECT ...
WHERE str LIKE 'pu3q0k0vw%' AND -- the 10-char set
str REGEXP '^pu3q0k0vw[nprqmj]' -- the 9 next letters
LIMIT ...
# then check for 450; if not enough, continue...
SELECT ...
WHERE str LIKE 'pu3q0k0vt%' AND -- the 10-char set
str REGEXP '^pu3q0k0vt[vyz]' -- the 9 next letters
LIMIT 450
# then check for 450; if not enough, continue...
etc.
SELECT ...
WHERE str LIKE 'pu3q0k0v%' AND -- the 9-char set
str REGEXP '^pu3q0k0v[wyzxrqmtv]' -- the 9 next letters
LIMIT ...
# check, etc; for a total of 10 SELECTs or 450 rows, whichever comes first.
这将是 10+ select 秒。每个 select 将通过首先选择具有 LIKE 公共前缀的行进行某种程度的优化,然后使用 REGEXP 进行双重检查。
(如果您不喜欢将不一致的 pu3q0k0vw
与 pu3q0k0vt
分开;我们可以进一步讨论。)
你说"prefix";我已经对 LIKE 和 REGEXP 进行了编码,以假定任意文本 在 给定的前缀之后。
UNION
不可行,因为它(我认为)会在选择 450 之前收集所有行。每个 SELECT
将停在 LIMIT
if 没有 DISTINCT
GROUP BY
或 ORDER BY
需要先收集所有东西。
REGEXP
不够智能,无法避免扫描整个 table;添加 LIKE
可以避免这种情况(除非有超过 20% 的行与 LIKE
匹配)。