简单的子查询在巨大的桌子上放慢速度

时间:2017-08-23 22:51:02

标签: mysql sql database

所以我得到了一个包含2个表的mysql数据库,其中一个(sd_clients)包含大约24k个条目:

CREATE TABLE `sd_clients` (
  `ms_id` varchar(10) NOT NULL,
  `ms_share_id` varchar(10) NOT NULL,
  `short_name` varchar(25) DEFAULT NULL,
  `standard_name` varchar(75) DEFAULT NULL,
  `legal_name` varchar(150) DEFAULT NULL,
  `country` varchar(4) DEFAULT NULL,
  `status` tinyint(1) DEFAULT NULL COMMENT '1=Paid Client | 2=Non-Paid Client',
  `user_id` int(11) DEFAULT NULL,
  `summary` text,
  `sector` int(4) DEFAULT NULL,
  `sub_sector` int(4) DEFAULT NULL,
  `business_country` char(3) DEFAULT NULL,
  `created_at` date DEFAULT NULL,
  `is_paid` int(1) NOT NULL DEFAULT '0' COMMENT '0 = Non-Paid Client | 1=Paid Client',
  `description_en` text,
  `description_zh-hans` text,
  `description_zh-hant` text,
  `highlights_en` text,
  `highlights_zh-hans` text,
  `highlights_zh-hant` text,
  `logo` varchar(255) DEFAULT NULL,
  `summary_subsection_title_en` varchar(500) DEFAULT NULL,
  `summary_subsection_title_zh-hans` varchar(500) DEFAULT NULL,
  `summary_subsection_title_zh-hant` varchar(500) DEFAULT NULL,
  `summary_subsection_text_en` text,
  `summary_subsection_text_zh-hans` text,
  `summary_subsection_text_zh-hant` text,
  `summary_short_en` varchar(2000) DEFAULT NULL,
  `summary_short_zh-hans` varchar(2000) DEFAULT NULL,
  `summary_short_zh-hant` varchar(2000) DEFAULT NULL,
  `other_information_en` text,
  `other_information_zh-hans` text,
  `other_information_zh-hant` text,
  `change_percentage` decimal(10,3) DEFAULT NULL,
  `id_sector` bigint(3) DEFAULT NULL,
  `id_subsector` bigint(3) DEFAULT NULL,
  `background_info_en` text,
  `background_info_zh-hans` text,
  `background_info_zh-hant` text,
  `share_id_displayed` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`ms_id`) KEY_BLOCK_SIZE=1024,
  UNIQUE KEY `ms_id` (`ms_id`) KEY_BLOCK_SIZE=1024,
  KEY `share_id_displayed` (`share_id_displayed`) KEY_BLOCK_SIZE=1024
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
SET FOREIGN_KEY_CHECKS=1;

另一个叫做sd_clients_daily_stocks,有大约5000万个条目:

CREATE TABLE `sd_clients_daily_stocks` (
  `ms_id` varchar(10) NOT NULL,
  `ms_share_id` varchar(10) DEFAULT NULL,
  `created_at` date DEFAULT NULL,
  `symbol` varchar(32) DEFAULT NULL,
  `exchange_id` char(5) DEFAULT NULL,
  `volume` bigint(18) DEFAULT NULL,
  `day_low` decimal(19,6) DEFAULT NULL,
  `day_high` decimal(19,6) DEFAULT NULL,
  `market_cap` bigint(18) DEFAULT NULL,
  `open_price` decimal(19,6) DEFAULT NULL,
  `close_price` decimal(19,6) DEFAULT NULL,
  `enterprise_value` bigint(18) DEFAULT NULL,
  `currency_id` char(3) DEFAULT NULL,
  `valoren` varchar(20) DEFAULT NULL,
  `cusip` char(9) DEFAULT NULL,
  `isin` varchar(12) DEFAULT NULL,
  `sedol` varchar(7) DEFAULT NULL,
  `ipo_date` date DEFAULT NULL,
  `is_depositary_receipt` tinyint(1) DEFAULT NULL,
  `depositary_receipt_ratio` decimal(9,4) DEFAULT NULL,
  `security_type` char(10) DEFAULT NULL,
  `share_class_description` varchar(1000) DEFAULT NULL,
  `share_class_status` char(1) DEFAULT NULL,
  `is_primary_share` tinyint(1) DEFAULT NULL,
  `is_dividend_reinvest` tinyint(1) DEFAULT NULL,
  `is_direct_invest` tinyint(1) DEFAULT NULL,
  `investment_id` char(10) DEFAULT NULL,
  `ipo_offer_price` decimal(19,6) DEFAULT NULL,
  `delisting_date` date DEFAULT NULL,
  `delisting_reason` varchar(100) DEFAULT NULL,
  `mic` char(10) DEFAULT NULL,
  `common_share_sub_type` varchar(32) DEFAULT NULL,
  `ipo_offer_price_range` varchar(32) DEFAULT NULL,
  `exchange_sub_market_global_id` char(10) DEFAULT NULL,
  `conversion_ratio` decimal(19,9) DEFAULT NULL,
  KEY `ms_id` (`ms_id`) USING HASH,
  KEY `ms_share_id` (`ms_share_id`) USING HASH,
  KEY `symbol` (`symbol`),
  KEY `exchange_id` (`exchange_id`),
  KEY `created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
SET FOREIGN_KEY_CHECKS=1;

我正在尝试运行一个相当简单的查询:

SELECT DISTINCT
	sd_clients.ms_id, 
	sd_clients.standard_name, 
	sd_clients.is_paid, 
	sd_clients.logo,
	sd_clients.change_percentage,
	(
		SELECT 
			CONCAT(
					`exchange_id`, '|--|', 
					`symbol`, '|--|', 
					`close_price`, '|--|', 
					`day_low`, '|--|', 
					`day_high`
			) as items
		FROM sd_clients_daily_stocks 
		WHERE ms_share_id = sd_clients.share_id_displayed 
		ORDER BY created_at DESC 
		LIMIT 1
	) as company_data
FROM sd_clients 
GROUP BY ms_id 
ORDER BY sd_clients.standard_name ASC
LIMIT 10

但由于某种原因,它花了太长时间(比如超过1分钟),得到任何结果,任何想法为什么?

顺便说一下,如果删除子查询,它的工作正常,但我需要它,因为其余数据在另一个表中。另外,我知道我可以在没有子查询的情况下获得结果,但我还有其他查询,其中子查询必须在那里。

我还注意到,如果在子查询中使用字符串而不是“sd_clients.share_id_displayed”,它会变得非常快。

2 个答案:

答案 0 :(得分:1)

您应该在sd_clients_daily_stocks(ms_share_id, created_at)上尝试索引。

如果您想要覆盖索引,可以添加select中的其他列。

答案 1 :(得分:0)

根据您当前的子查询加入非相关子查询可能会更好;使用这种技术here在新子查询中查找每个最新的行。

编辑:我在想更多这样的事情:

SELECT DISTINCT sd_clients.ms_id, sd_clients.standard_name, sd_clients.is_paid, sd_clients.logo, sd_clients.change_percentage
    , scdsB.items
FROM sd_clients 
INNER JOIN ( 
    SELECT scdsA.ms_share_id
        , CONCAT(
            scdsA.`exchange_id`, '|--|', scdsA.`symbol`, '|--|', 
            scdsA.`close_price`, '|--|', scdsA.`day_low`, '|--|', scdsA.`day_high`
        ) as items
    FROM sd_clients_daily_stocks AS scdsA
    INNER JOIN (
        SELECT ms_share_id, MAX(created_at)
        FROM sd_clients_daily_stocks
        GROUP BY ms_share_id 
    ) AS lasts
    ON scdsA.ms_share_id = lasts.ms_share_id
    AND scdsA.created_at = lasts.created_at
) scdsB 
ON sd_clients.share_id_displayed = scdsB.ms_share_id 
GROUP BY sd_clients.ms_id 
ORDER BY sd_clients.standard_name ASC 
LIMIT 10;

......但即便如此,如果有的话,这可能会在12秒内降低速度。此时,您最好查看可能有用的索引。例如,查找每个lasts值的最新(最大)created_at值的ms_share_id分组子查询将受益于sd_clients_daily_stocks (ms_shared_id, created_at)上的索引,就像加入它一样用于。