MySQL:优化查询以从字符串集中查找匹配的字符串

时间:2016-01-02 10:23:31

标签: mysql query-optimization query-performance

我有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

要求: 我有一个表PROFILES有列SRNO(类型bigint,主键)和UNIQUESTRING(类型char(10),唯一键)。我想找到450个SRNO来匹配那10套中的UNIQUESTRING。

首先在第一组中找到之类的字符串。如果我们没有获得足够的结果(即450),请在第二组中找到之类的字符串。如果我们仍然没有获得足够的结果(450减去第一组的结果),请在第三组中找到之类的字符串。等等。

现有解决方案: 我写了类似的查询:

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的反馈意见后answer我意识到这不是优化查询,因为它涉及的行数超过了它需要的很多行。 所以我打算像这样重写查询:

(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 

我想知道是否有更好的解决方案可以做到这一点。

1 个答案:

答案 0 :(得分:1)

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多个选择。通过首先选择具有LIKE的公共前缀的行,然后使用REGEXP进行双重检查,每个选择都会稍微优化。

(如果您不喜欢将不一致的pu3q0k0vwpu3q0k0vt分开;我们可以进一步讨论。)

你说"前缀&#34 ;;我已经将LIKE和REGEXP编码为在给出前缀之后假定任意文本

UNION不可行,因为它(我认为)会在选择450之前收集所有行。如果<{em>} <{em>},SELECT 将会停在LIMIT 没有DISTINCT GROUP BYORDER BY需要先收集所有内容。

REGEXP不够智能,无法扫描整个表格;添加LIKE可以避免这种情况(例如,超过20%的行与LIKE匹配时除外)。