【问题标题】:SQL - Strange issue with SELECTSQL - SELECT 的奇怪问题
【发布时间】:2016-08-07 02:01:33
【问题描述】:

我有一个奇怪的情况,从下表中按列pqth_scan_code 进行简单选择:

表 pqth_

Field           Type         Null   Key     Default     Extra   
pqth_id         int(11)      NO     PRI     NULL        auto_increment
pqth_scan_code  varchar(250) NO             NULL    
pqth_info       text         YES            NULL    
pqth_opk        int(11)      NO             999

查询 1

此查询执行耗时 12.7221 秒

SELECT * FROM `pqth_` WHERE pqth_scan_code = "7900722!30@3#6$EN" 

查询 2 此查询执行耗时 0.0003 秒

SELECT * FROM `pqth` WHERE `pqth_id`=27597 

基于表 pqth_ 中的数据,我创建了下表,其中 pqthc_id = pqth_idpqthc_scan_code=pqth_scan_code

表 pqthc

Field           Type         Null   Key     Default     Extra   
pqthc_id        int(11)      NO     PRI     NULL    
pqthc_scan_code tinytext     NO             NULL    

在表pqthc 上执行相同的查询query1 耗时 0.0259 秒

SELECT * FROM `pqthc` WHERE pqthc_scan_code = "7900722!30@3#6$EN"

如果我运行下面的查询会花费 0.0971 秒,很奇怪。

查询 3

SELECT * FROM `pqth` WHERE pqth_id = (SELECT pqthc_id From pqthc where pqthc_scan_code = "7900722!30@3#6$EN")

我的问题是为什么 pqth_scan_code 的 SELECT 速度很慢,而 pqth_id 的 SELECT 速度最快?这两列都有索引。

如需测试,请从link 获取导出

MySQL 和 MariaDB 服务器的行为相同

【问题讨论】:

  • 据我所知,与按数字搜索相比,在 MySQL 中基于文本的搜索要得多。我认为这就是问题所在。
  • 您是否尝试过在 SQL 中针对所有相应的查询执行执行计划?这可能会给你答案。快速说明, pqthc_scn_code 无论如何都是 varchar 并且没有索引,它必须花费时间来获取数据。是的,引擎在内存中检索到的列数会影响 I/O 操作,从而影响最终时间。您将在执行计划中看到这一点。

标签: mysql sql mariadb


【解决方案1】:
SELECT * FROM `pqth_` WHERE pqth_scan_code = "7900722!30@3#6$EN" 

需要INDEX(pqth_scan_code)。时期。讨论结束。

SELECT * FROM `pqth` WHERE `pqth_id`=27597 

有一个有用的索引,因为 PRIMARY KEY 是一个索引(并且它是唯一的)。

SELECT * FROM `pqthc` WHERE pqthc_scan_code = "7900722!30@3#6$EN"

还需要INDEX(pqthc_scan_code)。但它可能更快,因为 (1) 表更小,或者 (2) 您之前运行过查询,从而在 RAM 中缓存了所需的内容。

请不要在列名前加上表名。
请不要让表名彼此靠近以至于难以区分。 (pqthpqthc

SELECT  *
    FROM  `pqth`
    WHERE  pqth_id = 
      ( SELECT  pqthc_id
            From  pqthc
            where  pqthc_scan_code = "7900722!30@3#6$EN"
      )

构造IN ( SELECT ... ) 效率不高。

很少有两个表具有相同的PRIMARY KEY;你确定你是那个意思吗?

改用JOIN

SELECT  a.*
    FROM  `pqth` AS a
    JOIN  pqthc AS c ON a.id = c.id
    where  c.scan_code = "7900722!30@3#6$EN" 

如果那是“正确的”,那么我推荐这个“覆盖”索引:

INDEX(scan_code, id)

而不是我之前推荐的较短的INDEX(scan_code)

More on indexing.

【讨论】:

  • 谢谢你的好回答。表 pqthc 仅用于测试查询 SELECT a.* FROM pqth` AS a JOIN pqthc AS c ON a.id = c.id where c.scan_code = "7900722!30@3#6$EN" ` 。如果更糟糕,也是一个连接查询。在列scan_code 上添加索引解决了这个问题。
【解决方案2】:

首先pqthc_scan_code 没有索引/键,pqthc_id 有,键有助于加快搜索速度。

另一个区别是pqthc_id 是一个整数,而pqthc_scan_code 是一个字符串。比较整数比比较字符串要高效得多。

您应该避免在非常大的表中搜索字符串。

您可以向pqthc_scan_code 添加索引/键,但我不知道它会有多大帮助。

您可以在查询的前面使用 EXPLAIN 来尝试找出需要这么长时间 More info on EXPLAIN

【讨论】:

  • 但是同一个查询,查询1和查询2,在两个表上的执行时间不同,
  • 我假设另一个表的行数较少?这有点令人困惑,因为您有一个名为“pqth”、“pqth_”和“pqhtc”的表格?
  • 其他表有更多行和更多列。表pqth_pqth 表的1:1 副本,用于测试。此外,我还有另一个表,其中包含scan_code 的列比pqth 大,并且通过ascan_code 搜索更快。
  • 如果不能自己尝试就很难判断,您可以在 sql fiddle 中添加带有插入日期的两个表并在此处发布。或者尝试在查询前使用 EXPLAIN,看看是什么花费了这么多时间
【解决方案3】:

您必须了解主键和索引的概念以及它们如何帮助搜索, 参考文档here

【讨论】:

  • 我知道这个概念,但是为什么query1比query 2花费更多时间。表中的列数对查询有这么大的影响?
猜你喜欢
  • 1970-01-01
  • 2011-02-02
  • 2012-01-20
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多