【发布时间】:2018-02-03 10:29:24
【问题描述】:
我有两个表,它们之间的连接需要很长时间。创建了相关索引,但显然它没有被使用是我的猜测。
表 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_SYMBOL 和 AS_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 行。
SELECT COUNT(*) FROM INTRADAY_PRICES_CASH C WHERE 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';
select @@innodb_buffer_pool_size 是 133.2 G
我有 16GB 内存。
【问题讨论】:
-
您需要额外的索引
INTRADAY_PRICES_CASH(SnapshotDate, TradingSymbol)或ACTIVE_INSTRUMENTS_CASH(TRADING_SYMBOL, AS_ON_DATE)。列的顺序很重要,目前您的两个表中的 2 列索引不同。 -
谢谢。两者都加了。虽然解释显示它正在使用 INTRADAY_PRICES_CASH(SnapshotDate, TradingSymbol),但仍然需要 36 分钟。这些是索引:
KEYIND5` (TRADING_SYMBOL,AS_ON_DATE)` 和KEYIDX_SNAPSHOTDATETRADINGSYMBOL` (SnapshotDate,TradingSymbol)`。说明显示:表类型可能键键 I 范围 IND_AS_ON_DATE,IND1,IND3,IND5 IND_AS_ON_DATE C ref IDX_SNAPSHOTDATE,IDX_SNAPSHOTDATETRADINGSYMBOL IDX_SNAPSHOTDATETRADINGSYMBOL -
你得到的计数是多少,你的表中有多少行?这是一个非常简单的查询,可以完全从索引中计算出来,即使您的表中有十亿行,也不应该花费 36 分钟。
TradingSymbol包含/是否包含更可能 10 个或更可能 100 个字符?将其替换为表示该符号的 int 可以提高速度(相对于符号的平均长度)。 -
INTRADAY_PRICES_CASH 包含 69700675 行。 ACTIVE_INSTRUMENTS_CASH 包含 190177 行。我会检查字符集然后回来。 TradingSymbol 包含代表股票代码的字符...如 APPLE、AMAZON 等。
-
啊。我刚刚看到是什么原因造成的。
tradingSymbol和TRADING_SYMBOL都需要具有相同的字符集/排序规则,因此请替换一个(您可能应该使用 utf8 以使其最灵活)。如前所述,更可取的是用 int 替换它,但修复字符集更容易,并且应该已经带来了很大的改进。
标签: mysql join indexing fulltext-index