Mysql 使用多个LIKE语句和REGEXP的查询能否更高效?

Mysql 使用多个LIKE语句和REGEXP的查询能否更高效?,mysql,sql,mysql5,Mysql,Sql,Mysql5,我正在构造一个动态查询,从数据库中选择删除的域名。目前有十几行,但我将很快获得数据,其中将有多达500000行的记录 架构只是一个包含4列的表: CREATE TABLE `DroppedDomains` ( `domainID` int(11) NOT NULL AUTO_INCREMENT, `DomainName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `DropDate` date DEFAULT NULL,

我正在构造一个动态查询,从数据库中选择删除的域名。目前有十几行,但我将很快获得数据,其中将有多达500000行的记录

架构只是一个包含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
我没有创建模式,这是实时数据库模式。以下是示例数据:

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

选择任意数量的域

  • 从“开始”这个词开始
  • 用“结束”这个词结束
  • 在域名中的任何位置包含单词“containsThis”
  • 在域名中的任何位置包含单词“containsthisto”
  • 包括至少一个数字
  • 域名必须至少包含49个字符。多字节需要计数 作为一个字符(我使用字符长度 )
  • 域名必须至少少于65个字符
  • TLD必须为“组织”
  • 删除日期必须晚于
    2009-11-01
  • 以下是我目前的疑问:

    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=1
    和域名,如“开始%结束”
    和域名,如“%containsThis%”
    和域名,如“%containsthistoro%”
    和类似“%-%”的域名
    和域名REGEXP'[0-9]'
    和字符长度(域名)>49
    和字符长度(域名)<65
    TLD='org'
    和删除日期>'2009-11-01'
    
    以下是我的问题

  • 如果我将
    TLD
    列作为自己的表,并将
    TLD
    列作为外键,那么考虑到我将有50万行,这会极大地提高性能吗?只有5个TLD(com、net、org、info、biz)。我意识到现实世界中有更多的TLD,但这个应用程序只有5个TLD。用户无法指定自己的TLD

  • 我知道,
    REGEXP
    和500000行可能会导致灾难。我是否可以避免使用
    REGEXP

  • 我还可以对查询进行其他优化吗?像merge
    Like
    s或使用其他功能,例如可能
    INSTR
    ?我应该实现任何特定类型的缓存机制吗


  • 如果有一个以常量前缀开头的相似模式,并且该字段上有一个索引,则可以使用该索引快速查找以前缀开头的行。幸运的是,您正处于这种情况:

    AND DomainName LIKE 'starts%ends'
    

    如果只有少数值以
    开始
    开始,则将很快找到这些行,而其他表达式将仅针对这些行进行测试。您可以通过运行
    EXPLAIN SELECT…

    检查是否使用了索引。当您有一个以常量前缀开头的相似模式,并且该字段上有一个索引时,可以使用索引快速查找以前缀开头的行。幸运的是,您正处于这种情况:

    AND DomainName LIKE 'starts%ends'
    

    如果只有少数值以
    开始
    开始,则将很快找到这些行,而其他表达式将仅针对这些行进行测试。您可以通过运行
    EXPLAIN SELECT…

    检查是否使用了索引。您应该根据计划使用的查询计划要创建的索引

    • 如果您有查询,请选择该筛选器 仅按DropDate,然后按 DropDate将非常有用
    • 如果您有查询,请按分组 TLD,则TLD上的索引将 有用
    • 如果您有需要搜索的查询 只有域名的长度,然后 您可以考虑添加字段域名长度 有一个索引,所以 长度不是每小时计算一次的 运行查询的时间
    • 如果查询通过两个字段(例如TLD和DropDate)进行搜索(筛选),那么这些字段可能需要一个两列索引
    • 等等
    如果您将使用的唯一查询是您提到的复杂查询,那么Mark的建议(关于域名索引)是最好的

    关于问题1关于
    TLD
    字段:

    如果您真的只有少量(如5个)的选项,并且您不打算使用所有可用的TLD,那么您可以使用


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

    • 如果您有查询,请选择该筛选器 仅按DropDate,然后按 DropDate将非常有用
    • 如果您有查询,请按分组 TLD,则TLD上的索引将 有用
    • 如果您有需要搜索的查询 只有域名的长度,然后 您可以考虑添加字段域名长度 有一个索引,所以 长度不是每小时计算一次的 运行查询的时间
    • 如果查询通过两个字段(例如TLD和DropDate)进行搜索(筛选),那么这些字段可能需要一个两列索引
    • 等等
    如果您将使用的唯一查询是您提到的复杂查询,那么Mark的建议(关于域名索引)是最好的

    关于问题1关于
    TLD
    字段:

    如果您真的只有少量(如5个)的选项,并且您不打算使用所有可用的TLD,那么您可以使用


    注意:我知道我不应该使用
    SELECT.*
    ,因为将来可能会添加更多的列,而选择不必要的列可能会影响性能。它仅用于演示/测试目的。注意:我知道我不应该使用
    SELECT.*
    ,因为将来可能会添加更多列,而选择不必要的列可能会影响性能。这只是为了演示/测试的目的。那么这是否意味着我的查询几乎已经尽可能地优化了?@meder:如果你有正确的索引,那么是的。您可能还想在这里考虑多栏索引。