使用几个REGEXP时Mysql查询性能问题?

时间:2016-02-08 12:15:30

标签: mysql regex performance

在我的查询中,我需要有几个正则表达式来过滤用户名或电子邮件,因为我对它们并不感兴趣。所以,我已经在mysql中编写了这个查询,运行之后,花了这么多时间才给我回复结果。我的机智表现有问题。此外,运行此查询后,甚至不会以正确的方式过滤我的信息。我不确定如何改进我的查询以便:

  • 加快查询响应时间
  • 正确应用过滤 正则表达式

我将不胜感激任何帮助。

select DISTINCT t.user, vg_product_id,t.`platform`, pd.`mail`,
substring_index(group_concat(p.ts ORDER BY p.ts DESC SEPARATOR ','), ',', 1) as sub_start_ts, 
substring_index(group_concat(t.`expires_at`ORDER BY t.`expires_at` DESC SEPARATOR ','), ',', 1) as expired_time 
from users u
inner join tariff_subs_info t on (t.`user` = u.`user_xmpp_login` 
                                  and t.`user` NOT REGEXP ('^([A-Za-z]{2,3}(produsero|usero)+[0-9]{1,3})$' or '(\w+|\d+)?test(\w+|\d+)?' )
                                  and t.vg_product_id REGEXP "^(europe?|usa?|unlimited?|basic?)([a-zA-Z0-9]+|\_)+(and?|ios?)+$" )
left  join plus_data pd on (u.`user_xmpp_login` = pd.`user`)
inner join purchase_log p on (p.purchase_id = t.purchase_id)
WHERE (pd.mail not like '%guerrillamail.com' 
       or pd.mail is null) 
group by 1,2 ORDER BY DATE(p.ts);

这是我的结果:

noadstestuser   basic_XXX_ios   ios NULL    2015-10-26 14:00:32 2015-10-26 14:05:24
brusero2    unlimited_XX_ios    ios brusero2@yhx.yg 2015-11-03 15:41:57 2015-11-03 15:46:45
brusero3    bXX_uscios  ios brusero3@tb.fff 2015-11-03 15:43:53 2015-11-03 15:48:42
esusero1    unliXX_usc  ios esusero1@es.userr   2015-11-03 13:51:54 2015-11-03 13:56:41
esusero3    basic_X_i os    esusero3@yn.yyf 2015-11-03 13:55:08 2015-11-03 14:00:02
esusero4    basic_X ios esusero4@yn.ttx 2015-11-03 14:01:50 2015-11-03 14:06:38
esusero5    unXXXed_us  ios esusero5@uh.hhb 2015-11-03 14:45:38 2015-11-03 14:50:24
esusero6    basic_XX    ios esusero6@yh.hvv 2015-11-03 14:51:22 2015-11-03 14:56:09
esusero7    unlimXX_    ios esusero7@yh.yyh 2015-11-03 15:20:35 2015-11-03 15:25:24
esusero8    basXX_usc   ios esusero8@ij.iih 2015-11-03 15:22:29 2015-11-03 15:27:14
flusero2    unlXXXe ios flusero2@yh.yog 2015-11-03 16:57:58 2015-11-03 17:02:45
nlprodusero1    baXicXX_X   ios nlprodusero1@yh.rof 2015-11-03 14:06:52 2015-11-03 14:11:44
nlprodusero2    unliXXXeds  ios nlprodusero2@uoh.df 2015-11-03 14:08:28 2015-11-03 14:13:16
prodpurchasetest    baXXc_usXc  ios NULL    2015-11-03 09:20:51 2015-11-03 09:25:41
ukusero1    basicXXsca  ios ukusero1@uj.uoh 2015-11-03 15:45:59 2015-11-03 15:48:42
ukusero2    baXXsca ios gbuser@yb.jov   2015-11-03 17:00:14 2015-11-03 17:05:07
ukusero4    unlXXd_usc  ios ukusero4@uoh.jv 2015-11-03 17:02:10 2015-11-03 17:02:45
usprodusero1    uXXited_us  ios usprodusero1@ook.ok 2015-11-03 13:30:25 2015-11-03 13:35:14
usprodusero2    bXXXs   ios usprodusero2@ok.iob 2015-11-03 13:33:39 2015-11-03 13:38:31
usprodusero5    unlXXsc ios usprodusero5@rou.tf 2015-11-03 15:34:35 2015-11-03 15:39:26

这个结果让我意外,我不想拥有它们。尽管使用了NOT REGEXP,但所有这些都是我的结果。我该如何解决这些问题?

编辑后:

select t.user, vg_product_id,t.`platform`, pd.`mail`,
substring_index(group_concat(p.ts ORDER BY p.ts DESC SEPARATOR ','), ',', 1) as sub_start_ts, 
substring_index(group_concat(t.`expires_at`ORDER BY t.`expires_at` DESC SEPARATOR ','), ',', 1) as expired_time 
from users u
inner join tariff_subs_info t on (t.`user` = u.`user_xmpp_login` 
                                  and t.`user` NOT REGEXP ('^([A-Za-z]{2,3}(produsero|usero)+[0-9]{1,3})$')
                                  and t.`user` NOT REGEXP ('test')
                                  and t.vg_product_id REGEXP ("^(europe?|usa?|unlimited?|basic?)([a-zA-Z0-9_]+)+(and?|ios?)+$" ))
left  join plus_data pd on (u.`user_xmpp_login` = pd.`user`)
inner join purchase_log p on (p.purchase_id = t.purchase_id)
WHERE (pd.mail not like '%guerrillamail.com' 
      and pd.mail NOT LIKE '%test%'
       or pd.mail is null) 
group by 1,2 ORDER BY DATE(p.ts);

我仍然有以下结果,并且'测试'在我的用户中。

noadstestuser   basixxxf_ios    ios NULL    2015-10-26 14:00:32 2015-10-26 14:05:24
prodpurchasetest    basic_uscaxxs   ios NULL    2015-11-03 09:20:51 2015-11-03 09:25:41
esusertest  basic_uscxxxs   ios esusertest@ixn.ib   2015-11-04 13:53:48 2015-11-04 13:58:44
esusertest2 basic_uxxxx ios esusertedt2@iu.ycx  2015-11-04 14:11:12 2015-11-04 14:13:44

2 个答案:

答案 0 :(得分:4)

MySQL REGEXP不支持\w\d速记字符类。因此,(\w+|\d+)?子模式在MySQL中无效。由于?量词使子模式可选(重复一次或零次),因此可以完全删除它们。

因此,or '(\w+|\d+)?test(\w+|\d+)?'将变为and t.`user` NOT REGEXP ('test'),但其含义与and t.`user` NOT LIKE '%test%'相同。

接下来,([a-zA-Z0-9]+|\_)+也很成问题,因为有一个嵌套量词(一个+在一个交替组内,其中应用了另一个+量词。这是可能发生灾难性回溯的经典场景。我建议用[a-zA-Z0-9_]+替换此子模式以匹配字母,数字或下划线。或其等效的[[:alnum:]_]+

答案 1 :(得分:1)

首先关闭:

t.`user` NOT REGEXP (
  'usero pattern' or
  'test pattern'
) 

不正确..你不能or两个字符串输入..你需要:

    t.`user` NOT REGEXP ('usero pattern')
AND t.`user` NOT REGEXP ('test pattern')

您应该首先直接在相关表上测试所有表达式,以确保逻辑存在..如@WiktorStribizew所述,字和数字字符集可能无法识别。

接下来我猜你在查询中不需要DISTINCT和GROUP BY,你可以放弃DISTINCT。

不幸的是,你的正则表达式会击中每一行......你可以做很多事情。

如果这是一次性查询,你可能只需要花时间。你可能应该运行一个EXPLAIN来检查没有发生任何疯狂的事情,但确定。

如果您定期运行查询,我建议您在保存行时通过应用程序拆分相关信息,然后索引生成的额外列,它不会被标准化..但它可能是性能的情况提升将使它值得。

<强>更新

例如,前两行可以保存为:

[user:'noadstestuser', is_usero:0, is_test:1],
[user:'brusero2',      is_usero:1, is_test:0]

然后你的

    t.`user` NOT REGEXP ('usero pattern')
AND t.`user` NOT REGEXP ('test pattern')

变得简单

    t.is_usero = 0 AND t.is_test = 0

快得多..如果有帮助,你可以索引这些字段。

当然,在保存每一行之前,您必须进行匹配,这可能更容易使用您的应用程序逻辑(例如PHP代码)。