mysql - 连接速度慢,varchar 列上未使用索引

标签 mysql join indexing fulltext-index

我有两个表,它们之间的连接需要很长时间。创建了相关索引,但显然它没有被使用,这是我的猜测。

表 1:

CREATE TABLE `INTRADAY_PRICES_CASH` (
`TradingSymbol` varchar(100) CHARACTER SET latin1 NOT NULL,
`SnapshotDateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP,
`Open` double NOT NULL,
`Low` double NOT NULL,
`High` double NOT NULL,
`Close` double NOT NULL,
`Volume` double NOT NULL,
`SnapshotDate` date NOT NULL,
`SnapshotTime` time NOT NULL,
 `UpdateToDBTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 PRIMARY KEY (`TradingSymbol`,`SnapshotDateTime`),
 KEY `IDX_SNAPSHOTDATE` (`SnapshotDate`),
 KEY `IDX_SNAPSHOTDATETIME` (`SnapshotDateTime`),
 KEY `IDX_SNAPSHOTTIME` (`SnapshotTime`),
 KEY `IDX_TRADINGSYMBOL` (`TradingSymbol`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

表 2:

CREATE TABLE `ACTIVE_INSTRUMENTS_CASH` (
  `INSTRUMENT_ID` bigint(20) NOT NULL AUTO_INCREMENT,
  `INSTRUMENT_TOKEN` bigint(20) DEFAULT NULL,
  `EXCHANGE_TOKEN` bigint(20) DEFAULT NULL,
  `TRADING_SYMBOL` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `INSTRUMENT_NAME` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL,
  `EXPIRY` date DEFAULT NULL,
  `LOT_SIZE` double DEFAULT NULL,
  `TICK_SIZE` float DEFAULT NULL,
  `INSTRUMENT_TYPE` varbinary(10) DEFAULT NULL,
  `SEGMENT` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `EXCHANGE` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `AS_ON_DATE` date NOT NULL,
  PRIMARY KEY (`INSTRUMENT_ID`),
  UNIQUE KEY `IND_AS_ON_DATE` (`AS_ON_DATE`,`TRADING_SYMBOL`),
  KEY `IND1` (`AS_ON_DATE`),
  KEY `IND2` (`INSTRUMENT_TOKEN`),
  KEY `IND3` (`TRADING_SYMBOL`),
  KEY `IND4` (`INSTRUMENT_TYPE`)
) ENGINE=InnoDB AUTO_INCREMENT=196606 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

表 2 将 TRADING_SYMBOLAS_ON_DATE 作为 PK。对于一个日期,此表中可能有多个交易代码。

在表 1 中,对于相同的交易代码和日期组合,我们将有多行代表该代码在同一日期的不同分钟的不同价格。

现在,我想连接这些表以了解两个表中的交易代码和日期组合匹配的行数。

SELECT COUNT(*) FROM INTRADAY_PRICES_CASH C, ACTIVE_INSTRUMENTS_CASH I
WHERE C.`SnapshotDate`>'2017-08-14'
AND I.`TRADING_SYMBOL`=C.`TradingSymbol`
AND I.`AS_ON_DATE`=C.`SnapshotDate`

解释表明它正在使用:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  I   range   IND_AS_ON_DATE,IND1,IND3    IND_AS_ON_DATE  3   \N  15066   Using where; Using index
1   SIMPLE  C   ref IDX_SNAPSHOTDATE    IDX_SNAPSHOTDATE    3   u754793479_stock.I.AS_ON_DATE   771 Using where; Using index

奇怪的是,我没有看到它使用与 TradingSymbol 相关的两个表中的任何索引。这可能会导致延迟。

这种理解是否正确?如果是,如何纠正以使其使用与交易代码相关的索引。我是否需要交易代码的全文索引才能使用它。

编辑

以下是一些额外的说明:

INTRADAY_PRICES_CASH 包含 69700675 行。 ACTIVE_INSTRUMENTS_CASH 包含 190177 行。

从 INTRADAY_PRICES_CASH C 中选择 COUNT(*) 个,其中 C.SnapshotDate>'2017-08-14' 返回 3911679 行

我的托管提供商未提供对 innodb_index_stats 的访问。因此无法触发此查询: SELECT *, stat_value * @@innodb_page_size FROM mysql.innodb_index_stats WHERE table_name = 'INTRADAY_PRICES_CASH' and stat_name = 'size' and indexname = 'IDX_SNAPSHOTDATETRADINGSYMBOL';

选择@@innodb_buffer_pool_size为133.2 G

我有 16GB 内存。

最佳答案

请选择更好的别名 - 两个表的开头都是 C 和 I。

请使用首选的JOIN...ON

SELECT  COUNT(*)
    FROM  INTRADAY_PRICES_CASH AS p
    JOIN  ACTIVE_INSTRUMENTS_CASH AS a
          ON  a.`TRADING_SYMBOL` = p.`TradingSymbol`
         AND  a.`AS_ON_DATE`     = p.`SnapshotDate` 
    WHERE  p.`SnapshotDate`>'2017-08-14'

请注意 key_len 只有 3,这意味着它仅使用索引的 DATE 部分。

TRADING_SYMBOLTradingSymbol 使用相同CHARACTER SETCOLLATION。 (建议您也将它们拼写相同。)不同的排序规则会阻止使用索引(针对该列)。

这不会给你相同的 COUNT(*) 吗?

SELECT  COUNT(*)
    FROM  INTRADAY_PRICES_CASH
    WHERE  p.`SnapshotDate`>'2017-08-14';

如果您从 15 号开始,为什么不说 >= ... 15 而不是 > ... 14?这适用于 DATETIME 以及 DATE

其他表是否使用INSTRUMENT_ID?或者可以删除该列并将 UNIQUE 键提升为 PRIMARY 吗?

如果您确实需要联接,那么我可能有其他索引建议。

关于mysql - 连接速度慢,varchar 列上未使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45880266/

相关文章:

sql - 从客户事件、SQL 中查找放弃的搜索

MySQL连接,连接表中的空行

python - 获取要在列表上使用的数据帧的索引

Solr 4.0 在字符串字段中搜索

mysql - 如何在存储过程中加入多个 SELECT?

php - 使用 PHP、Composer、NPM 通过 WSL 设置 LEMP 的网络问题

php - 使用php在目录中查找文件

Sqlite 使用 JOIN 和重复项减去总和(使用分组依据)

sql - 关于 SQL(特别是 tsql)中索引的几个 101 个问题

mySQL - 在插入之后/期间添加预定义的值?有更好的方法吗?