我很难确定如何查询/索引数据库。
情况非常简单。每次用户访问类别时,都会存储他/她的访问日期。我的目标是列出用户最近访问后添加元素的类别。
以下是两个表格:
CREATE TABLE `elements` (
`category_id` int(11) NOT NULL,
`element_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`added_date` datetime NOT NULL,
PRIMARY KEY (`category_id`,`element_id`),
KEY `index_element_id` (`element_id`)
)
CREATE TABLE `categories_views` (
`member_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
`view_date` datetime NOT NULL,
PRIMARY KEY (`member_id`,`category_id`),
KEY `index_element_id` (`category_id`)
)
查询:
SELECT
categories_views.*,
elements.category_id
FROM
elements
INNER JOIN categories_views ON (categories_views.category_id = elements.category_id)
WHERE
categories_views.member_id = 1
AND elements.added_date > categories_views.view_date
GROUP BY elements.category_id
说明:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: elements
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 89057
Extra: Using temporary; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: categories_views
type: eq_ref
possible_keys: PRIMARY,index_element_id
key: PRIMARY
key_len: 8
ref: const,convert.elements.category_id
rows: 1
Extra: Using where
每个表中大约有100k行,查询大约需要0.3秒,这对于应该为Web上下文中的每个用户操作执行的内容来说太长了。
如果可能,我应该添加哪些索引,或者我应该如何重写此查询以避免使用filesorts和临时表?
答案 0 :(得分:1)
如果每个成员的category_views数量相对较少,我建议您测试一个不同的查询:
SELECT v.*
FROM categories_views v
WHERE v.member_id = 1
AND EXISTS
( SELECT 1
FROM elements e
WHERE e.category_id = v.category_id
AND e.added_date > v.view_date
)
为了获得该查询的最佳性能,您需要确保拥有索引:
... ON elements (category_id, added_date)
... ON categories_views (member_id, category_id)
注意:看起来categories_views
表上的主键可能是(member_id, category_id)
,这意味着已存在适当的索引。
我假设(尽可能从原始查询中得出)是categories_views
表仅包含用户类别的“最新”视图,即{{1} } 是独特的。看起来情况必须如此,如果原始查询返回正确的结果集(如果它的唯一返回类别自用户的“最后一个视图”以来添加了“新”元素;否则,存在member_id, category_id
表中的任何“较旧”view_date
值都会触发包含该类别,即使有一个比最新categories_views
更新的view_date
更新added_date
})类别中的元素。
如果不是这种情况,即(member_id,category_id)
不是唯一的,则需要更改查询。
原始问题中的查询有点令人费解,它将element_views
引用为表名或表别名,但这不会出现在EXPLAIN输出中。我假设element_views
是categories_views
的同义词。
对于原始查询,在elements
表上添加覆盖索引:
... ON elements (category_id, added_date)
目标是让解释输出显示“使用索引”
您也可以尝试添加索引:
... ON categories_views (member_id, category_id, added_date)
要获取categories_view表中的所有列(对于选择列表),查询将不得不访问表中的页面(除非有包含所有这些列的索引。目标是减少通过使索引满足所有(或大多数)谓词,需要在数据页上访问以查找行的行数。
是否有必要从category_id
表中返回elements
列?我们不知道这与category_id
表的categories_views
列中的值相同,因为内连接谓词?