我试图为MySQL创建有效的SQL代码来获取一些值,但是以随机顺序和不同的数量。问题是表格很大(约4米的行,约400 MB),我没有太多时间去做(现在每次尝试大约需要1-2分钟)。此外,每列都有索引,但不是UNIQUE,它是字符串值,而不是自动包含。
我生成长SQL查询:
(SELECT fieldA,'id1' AS id FROM myTable WHERE (fieldB LIKE 'xxxx:%') ORDER BY RAND() LIMIT 7)
UNION ALL
(SELECT fieldA,'id2' AS id FROM myTable WHERE (fieldB ='123123') ORDER BY RAND() LIMIT 5)
etc...
我想只订购一次这个表(这需要花费很多时间)。我已经尝试过了:
我只有最后一个运气(III。来自OP的建议),但是16的“魔术”数字并没有诀窍 - 这对于较小的表而言并不适用于具有~4000000行的表。
这是示例EXPLAIN的输出:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY myTable range fieldB fieldB 143 NULL 64198 Using where; Using temporary; Using filesort
2 UNION myTable ALL NULL NULL NULL NULL 4386943 Using where; Using temporary; Using filesort
3 UNION myTable range fieldB fieldB 143 NULL 34374 Using where; Using temporary; Using filesort
4 UNION myTable ref fieldB fieldB 143 const 1999 Using where; Using temporary; Using filesort
5 UNION myTable range fieldB fieldB 143 NULL 1 Using where; Using temporary; Using filesort NULL
UNION RESULT <union1,2,3,4,5> ALL NULL NULL NULL NULL NULL
所以我的猜测是ORDER BY RAND是主要问题 - 它为每个UNION部件制作“使用临时;使用filesort”。
表格定义:
CREATE TABLE IF NOT EXISTS `myTable` (
`fieldA` varchar(42) NOT NULL,
`XYZ` varchar(36) NOT NULL,
`fieldB` varchar(47) NOT NULL,
KEY `fieldA` (`fieldA`),
KEY `XYZ` (`XYZ`),
KEY `fieldB` (`fieldB`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
它只存储简单的短字符串,但存在很多字符串。
任何建议,meaby有不同的方法吗?
@edit,现在我正在使用MySQL和PHP来实现它:
通过为
创建UNION,我获得了fieldB的所需值列表SELECT fieldB, "xxxx:%" AS orygLike FROM myTable WHERE fieldB LIKE "xxxx:%" GROUP BY fieldB
每个UNIONed查询的等 - 仅适用于那些处于LIKE模式的人,如果这是'='我已经知道哪个fieldB有效:)
然后我能够制作fieldBVal =&gt;的映射数组。 orygLIKE(例如"xxxx:yyyy"=>"xxxx:%"
)
我使用WHERE id IN (id1,id2,id3...)
按ID列出了可以使用的fieldA的所有ID - 这样我就可以使用所有ID。就在这里我将数组组合在一起,并使用array_rand选择随机ID。
简单:
SELECT * FROM myTable WHERE id IN (RndID1, RndID2, RndID3 etc...)
速度非常快,效果很好:)。
感谢fancyPants指向ID auto-inc字段
答案 0 :(得分:2)
你在那里有查询正在扫描表格的所有行。
从解释
中查看此行2 UNION myTable ALL NULL NULL NULL NULL 4386943 Using where; Using temporary; Using filesort
这也是一个巨大的性能杀手。使用表别名可以确切地查看它是哪个查询,并查看是否可以通过调整索引来执行某些操作。
也许你也可以重写你的查询只对表进行一次排序,然后复合索引甚至比拥有这3个单独的索引更好。
尝试使用此查询(但请注意,它不保证您获得7行,其中fieldB像'xxx:%'和5行,fieldB ='123123'等等上):
SELECT
fieldA,
CASE WHEN fieldB LIKE 'xxxx:%' THEN 'id1'
WHEN fieldB ='123123' THEN 'id2'
END AS id
FROM myTable
WHERE
(fieldB LIKE 'xxxx:%')
OR fieldB ='123123'
ORDER BY RAND()
LIMIT 12 /*7 + 5*/
编辑:
“LIKE'%'”当然没用,因为它会选择每一行。它文学上说“给我任何东西”。如果你想让它超快,这是一个想法:
添加如下列:
ALTER TABLE yourTableName ADD COLUMN id INT AUTO_INCREMENT PRIMARY KEY;
然后,您可以获得表中最大的ID并预先计算您的randoms:
SET @my_max := (SELECT MAX(id) FROM yourTableName);
SET @r := RAND() * @my_max;
SELECT * FROM yourTable WHERE id >= @r LIMIT 1;
如果您需要更多,请再次执行此操作。我做了>=
和LIMIT 1
而不是简单的id = @r
,以防你删除某些行。
至少这部分查询是快速的。