提问人:ipel 提问时间:9/25/2023 最后编辑:Your Common Senseipel 更新时间:9/25/2023 访问量:99
1 个查询,用于选择同一表中不同类别中的多行
1 query to select multiple rows in the same table but in different category
问:
我有一个 PHP 脚本,它使用 4 个单独的查询从一个 mysql 表中读取最后 25 行(总共 100 行)。
例:
SELECT * FROM table WHERE datetime <= 'xxx' AND name = 'john' AND category = 'cat1' ORDER BY datetime DESC LIMIT 25
SELECT * FROM table WHERE datetime <= 'xxx' AND name = 'doe' AND category = 'cat1' ORDER BY datetime DESC LIMIT 25
SELECT * FROM table WHERE datetime <= 'xxx' AND name = 'john' AND category = 'cat2' ORDER BY datetime DESC LIMIT 25
SELECT * FROM table WHERE datetime <= 'xxx' AND name = 'doe' AND category = 'cat2' ORDER BY datetime DESC LIMIT 25
我使用 4 查询,因为我必须读取不同的记录,基于:名称和类别,两者都是索引。Datetime 也是一个索引。
但是这种方式很慢(表大约是60MB,250K行)。我想知道这是否可以通过 1 个查询以更快的方式完成。
编辑mysql表结构
CREATE TABLE IF NOT EXISTS table (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`category` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`data1` double NOT NULL,
`data2` double NOT NULL,
`data3` double NOT NULL,
#....
`data50` double NOT NULL,
PRIMARY KEY (`id`),
KEY `datetime` (`datetime`),
KEY `category` (`category`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
答:
1赞
user1191247
9/25/2023
#1
如果要一起运行查询,可以使用 UNION ALL
将查询结果组合在一起:
(
SELECT *
FROM `table`
WHERE datetime <= 'xxx' AND name = 'john' AND category = 'cat1'
ORDER BY datetime DESC
LIMIT 25
) UNION ALL (
SELECT *
FROM `table`
WHERE datetime <= 'xxx' AND name = 'doe' AND category = 'cat1'
ORDER BY datetime DESC
LIMIT 25
) UNION ALL (
SELECT *
FROM `table`
WHERE datetime <= 'xxx' AND name = 'john' AND category = 'cat2'
ORDER BY datetime DESC
LIMIT 25
) UNION ALL (
SELECT *
FROM `table`
WHERE datetime <= 'xxx' AND name = 'doe' AND category = 'cat2'
ORDER BY datetime DESC
LIMIT 25
)
请注意,由于 and 子句,各个查询需要括在括号中。ORDER BY
LIMIT
添加复合索引:
ALTER TABLE `table` ADD INDEX (category, name, datetime);
您可以删除单列索引,因为它是此新索引中的第一列。category
评论
0赞
ipel
9/26/2023
谢谢!我现在正在测试它。综合指数的顺序重要吗?
1赞
user1191247
9/26/2023
对于此查询,类别和名称可能不会有任何区别,但日期时间应该在末尾。
0赞
ipel
9/27/2023
如果我正确理解了 compsite 索引,在这种情况下,我应该移动 where 子句以遵循复合索引顺序,因此: WHERE category = 'cat2' AND name = 'doe' AND datetime <= 'xxx'
1赞
user1191247
9/27/2023
在 where 子句中,列的顺序没有区别。优化器将对事物的顺序做出自己的决定。
1赞
P.Salmon
9/25/2023
#2
例如,您可以通过分配行号在单个查询中执行此操作
create table t(id int,category varchar(4),name varchar(20));
insert into t values
(1,'cat1','john'),(2,'cat1','john'),(3,'cat1','john'),(20,'cat1','john'),(30,'cat1','john'),
(4,'cat2','john'),(5,'cat2','john'),(6,'cat2','john'),(50,'cat2','john'),
(7,'cat1','doe'),(8,'cat1','doe'),(9,'cat1','doe'),
(10,'cat2','doe'),(11,'cat2','doe'),(12,'cat2','doe'),(120,'cat2','doe');
with cte as(
select *,
row_number() over (partition by name,category order by id desc) rn
from t
where id < 20 and name in('john','doe') and category in('cat1','cat2'))
select * from cte
where rn < 3
order by name,category;
您需要自己测试这是否比您拥有的更快
评论
(category, name, datetime)
CREATE TABLE
EXPLAIN
UNION ALL
WHERE
WHERE datetime <= 'xxx' AND name IN ('john', 'doe') AND category IN ('cat1', 'cat2')
WHERE