我正在尝试optimize
mysql
一个完美运行但查询时间过长的查询。我的库存表几乎 300,000条记录(还不错)。我不确定使用subquery
或join
或其他index
会加快我的搜索结果。我确实在学生和库存表中都有索引的district_id列。
基本上,下面的query
会拉出教师名单中所有学生的所有库存。因此,首先必须搜索学生表以查找哪些学生在教师名单中,然后必须在每个学生的库存表中搜索。因此,如果教师有30多名学生,则可以通过库存进行大量搜索,每个学生可以拥有30多个库存。任何意见将是有益的!
SELECT inventory.inventory_id, items.title, items.isbn, items.item_num,
items.price, conditions.condition_name, inventory.check_out,
inventory.check_in, inventory.student_id, inventory.teacher_id
FROM inventory, conditions, items, students
WHERE students.teacher_id = '$teacher_id'
AND students.district_id = $district_id
AND inventory.student_id = students.s_number
AND inventory.district_id = $district_id
AND inventory.item_id = items.item_id
AND items.consumable !=1
AND conditions.condition_id = inventory.condition_id
ORDER BY inventory.student_id, inventory.inventory_id
这是表结构:
CREATE TABLE `inventory` (
`id` int(11) NOT NULL,
`inventory_id` varchar(10) CHARACTER SET utf8 NOT NULL DEFAULT '0',
`item_id` int(6) NOT NULL DEFAULT '0',
`district_id` int(2) NOT NULL DEFAULT '0',
`condition_id` int(1) NOT NULL DEFAULT '0',
`check_out` date NOT NULL DEFAULT '0000-00-00',
`check_in` date NOT NULL DEFAULT '0000-00-00',
`student_id` varchar(10) CHARACTER SET utf8 NOT NULL DEFAULT '0',
`teacher_id` varchar(6) CHARACTER SET utf8 NOT NULL DEFAULT '0',
`acquisition_date` date NOT NULL DEFAULT '0000-00-00',
`notes` text CHARACTER SET utf8 NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
答案 0 :(得分:0)
首先,你重写它以使用显式JOIN:
SELECT inventory.inventory_id,
items.title, items.isbn, items.item_num, items.price,
conditions.condition_name,
inventory.check_out, inventory.check_in,
inventory.student_id, inventory.teacher_id
FROM inventory
JOIN conditions ON (conditions.condition_id = inventory.condition_id)
JOIN items ON (inventory.item_id = items.item_id AND items.consumable != 1)
JOIN students ON (inventory.student_id = students.s_number)
WHERE students.teacher_id = '$teacher_id'
AND students.district_id = $district_id
AND inventory.district_id = $district_id
ORDER BY inventory.student_id, inventory.inventory_id
然后检查JOIN。例如:
JOIN items ON (inventory.item_id = items.item_id AND items.consumable != 1)
表示需要在item_id和耗材上扫描items表,可能是常量。如果可能的话,最好不要使用负面条件。但至少你在item_id上索引项目(除非它已经是主键,很可能)。如果消费品可以假设,例如,值0,1,2,3,那么你去:
JOIN items ON (inventory.item_id = items.item_id AND items.consumable IN (0, 2, 3))
并使用CREATE INDEX在耗材上添加索引。
您可能会注意到,库存中的一些列总是在其他JOIN中使用,并且还存在一些常量约束。
所以另一个有用的索引可能是
CREATE INDEX ... ON inventory(district_id, student_id, item_id, condition_id)
另一个有用的索引是
ON学生(teacher_id,district_id,student_id,s_number)
允许立即限制所涉及的学生的WHERE,并在不加载表的情况下检索JOIN所需的信息,只使用索引。
答案 1 :(得分:0)
切换到InnoDB!我要说的一些内容在InnoDB中效率较低。
SELECT i.inventory_id,
items.title, items.isbn, items.item_num, items.price,
c.condition_name,
i.check_out, i.check_in, i.student_id, i.teacher_id
FROM inventory AS i
JOIN conditions AS c ON c.condition_id = i.condition_id
JOIN items ON i.item_id = items.item_id
JOIN students AS s ON i.student_id = s.s_number
WHERE s.teacher_id = '$teacher_id'
AND s.district_id = $district_id
AND i.student_id = s.s_number
AND i.district_id = $district_id
AND items.consumable != 1
ORDER BY i.student_id, i.inventory_id
如果希望以students
:
students: INDEX(district_id, teacher_id, s_number)
注意:这也是"覆盖",从而避免索引BTree和数据BTree之间的弹跳。 (students
的PK是多少?请提供SHOW CREATE TABLE
。)
如果更好地使用ORDER BY
:
inventory: INDEX(district_id, student_id, inventory_id)
还需要:
items: (item_id) -- probably already the PRIMARY KEY?
conditions: (condition_id) -- probably already the PRIMARY KEY?
验证或添加这4个索引。 (优化程序将动态选择要执行的操作。)