我的查询多个LIKE语句和REGEXP可以更有效吗?

时间:2011-03-12 21:32:11

标签: mysql sql mysql5

我正在构建一个动态查询来从我的数据库中选择已删除的域名。目前有十几行,但我很快就会得到数据,这些数据的记录最多可达500,000行。

架构只是一个包含4列的表:

CREATE TABLE `DroppedDomains` (
  `domainID` int(11) NOT NULL AUTO_INCREMENT,
  `DomainName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  `DropDate` date DEFAULT NULL,
  `TLD` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`domainID`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

我没有创建架构,这是实时数据库架构。以下是示例数据:

enter image description here

我可能构建了下面最复杂的查询类型。标准如下:

选择任意数量的域

  
      
  1. 以“开始”一词开头
  2.   
  3. 以“结束”一词结尾
  4.   
  5. 在域名
  6. 的任何位置包含“containsThis”字样   
  7. 在域名
  8. 的任何位置包含“ContainsThisToo”字样   
  9. 包含至少一位数字
  10.   
  11. 域名必须至少为49个字符。多字节需要计数   作为一个角色(我使用CHAR_LENGTH   )。
  12.   
  13. 域名必须至少少于65个字符。
  14.   
  15. TLD必须是'org'
  16.   
  17. DropDate需要晚于2009-11-01
  18.   

到目前为止,这是我的查询:

SELECT
*
FROM
DroppedDomains

WHERE

1=1

AND DomainName LIKE 'starts%ends'
AND DomainName LIKE '%containsThis%'
AND DomainName LIKE '%containsThisToo%'
AND DomainName LIKE '%-%'
AND DomainName REGEXP '[0-9]'
AND CHAR_LENGTH(DomainName) > 49
AND CHAR_LENGTH(DomainName) < 65
AND TLD = 'org'
AND DropDate > '2009-11-01'

以下是我的问题

  1. 考虑到我有50万行,如果我将TLD列设置为自己的表,并将TLD列设为外键,那么它的性能会非常有益吗? ?只有5个TLD(com,net,org,info,biz)。我意识到现实世界中有更多TLD,但此应用程序只有5个。用户无法指定自己的TLD。

  2. 我知道REGEXP和500,000行可能是灾难的秘诀。无论如何我可以避免REGEXP吗?

  3. 我可以对查询进行其他任何优化吗?像合并LIKE或使用其他功能,如可能INSTR?我应该实现任何特定类型的缓存机制吗?

2 个答案:

答案 0 :(得分:3)

如果LIKE模式以常量前缀开头,并且您在该字段上有索引,那么索引可用于快速查找以前缀开头的行。幸运的是,你在这里遇到了这种情况:

AND DomainName LIKE 'starts%ends'

如果只有少数值以starts开头,则可以非常快速地找到这些行,并且仅针对这些行测试其他表达式。您可以通过运行EXPLAIN SELECT ...来检查是否使用了索引。

答案 1 :(得分:1)

您应该根据您计划使用的查询来规划要创建的索引。

  • 如果您有查询过滤 只有DropDate,然后是一个索引 DropDate很有用。
  • 如果您有分组的查询 TLD,然后是TLD的索引 是有用的。
  • 如果您有搜索查询 那么只有DomainName的长度 你可以考虑添加一个字段DomainNameLength 正是如此(以及对此的索引)所以 每次都不计算长度 你运行查询的时间。
  • 如果您有通过两个字段(例如TLD和DropDate)搜索(过滤)的查询,那么您可能需要在这些字段上使用2列索引。
  • 等...

如果您使用的唯一查询是您提到的复杂查询,那么Mark的建议(关于DomainName的索引)是最好的。

关于TLD字段的问题1:

如果您真的只有少量(如5个)选项,并且您不打算使用所有可用的tld,则可以使用ENUM type

CREATE TABLE(
   ....
   tld ENUM('com', 'net', 'org', 'info', 'biz')
)