所以我有两张桌子:
CREATE TABLE `adstable` (
`adid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`adbudget` decimal(14,7) unsigned NOT NULL DEFAULT '0.0000000',
`targetdesktop` tinyint(1) NOT NULL DEFAULT '1',
`adactive` tinyint(1) NOT NULL,
`user` bigint(20) unsigned NOT NULL,
`approved` tinyint(1) NOT NULL,
`imp_today` int(10) unsigned NOT NULL DEFAULT '0',
`targetwindows` tinyint(1) NOT NULL,
PRIMARY KEY (`adid`),
KEY `user_index` (`user`),
KEY `budget_index` (`adbudget`) USING BTREE,
KEY `imp_today_index` (`imp_today`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=719102 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT
CREATE TABLE `userstable` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`balance` decimal(14,7) unsigned NOT NULL DEFAULT '0.0000000',
PRIMARY KEY (`id`),
KEY `balance_index` (`balance`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT
我有两个MySQL查询:
SELECT adstable.adid FROM adstable INNER JOIN userstable ON (adstable.user = userstable.id )
WHERE
adstable.adactive=1 AND adstable.approved = 1 AND
adstable.targetdesktop = 1 AND adstable.targetwindows = 1 and
adstable.adbudget > 0.02 AND userstable.balance > 0.02
ORDER BY adstable.imp_today ASC limit 1
SELECT adstable.adid FROM adstable INNER JOIN userstable ON (adstable.user = userstable.id )
WHERE
adstable.adactive=1 AND adstable.approved = 1 AND
adstable.adbudget > 0.02 AND userstable.balance > 0.02
ORDER BY adstable.imp_today ASC limit 1
第一个查询在where子句中有一个额外条件: adstable.targetdesktop = 1 AND adstable.targetwindows = 1
然而,我无法理解的是为什么第一个查询需要2-3秒才能运行,而第二个查询需要2-3秒。
注意:
有没有人知道为什么第二个查询比第一个查询快得多,即使第二个查询返回的第一个#和第一个行的类型相同?
答案 0 :(得分:0)
您没有发布EXPLAIN
的输出,所以这是猜测。但是,您的第一个查询的条件似乎可能以某种方式迫使MySQL的查询规划器对您的adstable
进行全表扫描。它不是一张小桌子,所以扫描需要一段时间。
尝试在该表的(adactive, approved, adbudget, user)
上创建复合索引。这是您的查询的覆盖索引。您应该阅读有关覆盖索引的内容。
ALTER TABLE adactive
ADD INDEX act_appr_bud_user (adactive, approved, adbudget, user);
这应该允许查询计划程序随机访问并部分扫描索引以满足您的查询。它可能会加快速度。
注意(截至2017年初)MySQL的查询规划器通常每个表只能使用一个索引来满足查询。因此,单列上的大量索引无法像为特定查询选择的复合索引那样多。
答案 1 :(得分:0)
对于大型表格和LIMIT 1
,诀窍在于消耗整个WHERE
,以及ORDER BY
。这是不可能的,但这里的想法可能有帮助。
WHERE
adstable.adactive=1 AND
adstable.approved = 1 AND
adstable.targetdesktop = 1 AND
adstable.targetwindows = 1 and
adstable.adbudget > 0.02 AND
userstable.balance > 0.02
ORDER BY adstable.imp_today ASC limit 1
adstable
需要
INDEX(adactive, approved, targetdesktop, targetwindows, adbudget),
INDEX(adactive, approved, targetdesktop, targetwindows, imp_today)
前4列可以是任何顺序,但最后一列必须是最后一列。
第一个索引完全处理WHERE
的{{1}},但需要排序。第二个索引将执行一些过滤,但避免排序和短路adstable
。优化器可能(或可能不)选择两者中的较好者。
你可以将它们中的每一个扩展为"覆盖",但只能添加到列表的末尾。
在此
LIMIT 1
WHERE
adstable.adactive=1 AND
adstable.approved = 1 AND
adstable.adbudget > 0.02 AND
userstable.balance > 0.02
ORDER BY adstable.imp_today ASC limit 1
需要
adstable
前两列可以是任何顺序,但最后一列必须是最后一列。同样,他们最终可以扩展,使他们能够覆盖"。
如果您需要同时进行这两个查询,那么我建议您使用所有4个索引;没有一个是最佳的。
在这两种情况下,INDEX(adactive, approved, adbudget),
INDEX(adactive, approved, imp_today)
都需要userstable
,除非您已经拥有INDEX(id, balance)
。
PRIMARY KEY(id)
可以替换为
JOIN
这可能(或可能不会)影响表现。