Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 未使用数据库索引导致查询速度慢_Mysql_Sql_Database Indexes - Fatal编程技术网

Mysql 未使用数据库索引导致查询速度慢

Mysql 未使用数据库索引导致查询速度慢,mysql,sql,database-indexes,Mysql,Sql,Database Indexes,我有以下两个表格: StudentCourse - Id, - StudentId, - CourseId StudentId和CourseId上的唯一索引 学生ID和课程计数索引 关于Student2Id和CourseCount的索引 当我有一门课程时,我会列出参加课程的学生。我想完成的关键是在一个学生下面,我想列出他们以前与之一起学习过课程的其他学生 我正在尝试以下查询: SELECT * FROM StudentCourseCount sc INNER JOIN StudentC

我有以下两个表格:

StudentCourse
- Id, 
- StudentId, 
- CourseId  
StudentId和CourseId上的唯一索引

学生ID和课程计数索引

关于Student2Id和CourseCount的索引

当我有一门课程时,我会列出参加课程的学生。我想完成的关键是在一个学生下面,我想列出他们以前与之一起学习过课程的其他学生

我正在尝试以下查询:

SELECT * FROM StudentCourseCount sc
INNER JOIN StudentCourse s1 ON s1.course_id = <id> AND sc.student1_id = s1.student_id
INNER JOIN StudentCourse s2 ON s2.course_id = <id> AND sc.student2_id = s2.student_id
WHERE sc.course_count > 1
查询按预期工作;但是,在我的超大表10000000+行上,速度非常慢

当我解释查询时,StudentCourseCount没有使用索引。它正确地标识了Student1Id和Student2Id可能有索引,但不使用这两个索引

执行计划:表:sc可能的键:Student1Id,Student2Id键: 空行:28648392

表:c2键:学生id行:1

表:c1键:学生id行:1


第一个表是清晰的扫描,而不是使用键快速向下过滤。

似乎您也应该将课程id过滤器放在外部选择中。StudentCourseCount sc上唯一的过滤器是course\u count。假设您只搜索1个课程id,则应该让sc.course\u count>1和sc.course\u id=id。否则,是您的连接尝试将筛选器应用于sc.course\u count>1结果集


假设值分布均匀,则应执行此查询或变体。10M行不是非常大,它足够大,需要对查询进行优化。

我认为布伦特·贝斯利(Brent Baisley)有一个很好的观点,一开始我没有看到。我想你希望两个学生都在同一门课程中,这样你就可以在Join中链接他们,并在where子句中获得课程\ id=条件。我认为优化器应该自己做这些事情,但值得一试:

SELECT * FROM StudentCourseCount sc
INNER JOIN StudentCourse s1 ON sc.student1_id = s1.student_id
INNER JOIN StudentCourse s2 ON s2.course_id = s1.course_id AND sc.student2_id = s2.student_id
WHERE sc.course_count > 1 AND s1.course_id = <id> 

这是一个非常大的查询,返回非常大的结果集。我不确定您是否可以优化它,因为返回的数据量很大

SELECT *
FROM StudentCourseCount sc INNER JOIN
     StudentCourse s1
     ON s1.course_id = <id> AND sc.student1_id = s1.student_id INNER JOIN
     StudentCourse s2
     ON s2.course_id = <id> AND sc.student2_id = s2.student_id
WHERE sc.course_count > 1;
表中需要的索引是StudentCourseCountcourse\u count、student\u id和StudentCoursestudent\u id、course\u id

现在,您是说这个查询有效,我假设您的意思是您喜欢结果。它回答了以下问题:

获取所有参加过课程id并且参加过一门以上课程的学生

这与:

在“学生”下,我想列出以前与他们一起上课的其他学生


如果这是您真正的问题,我建议您在这里问另一个关于堆栈溢出的问题,以获得更好的查询。

您能复制表的执行计划和索引定义吗?我只是好奇。哪个应用程序在StudentCourse表中有10000000行?我添加了索引并描述了查询执行计划,但它没有很好地复制/粘贴,因此我重新编写了重要部分。专业提示:在软件中避免选择*,尤其是在访问大表的查询中。需要返回所有列会使优化器很难巧妙地满足您的查询。如果您重新编写查询以枚举所需的列,您将帮助我们推荐有用的索引策略。如果它对StudentCourseCount进行表扫描,我想其中sc.course_count>1不是选择性的,因为sc没有课程id,它包含学生及其计数。课程id在s1和s2表中进行筛选。啊,然后您似乎想先从StudentCourse表中选择,而不是从StudentCourseCount中选择。将s1.course\u id移动到where子句中会使速度更慢。所以这似乎没有什么帮助。好吧,然后再问一次,你在StudentCourseCount和StudentCourse中有多少记录?有多少StudentCourseCount记录符合course\u count>1的条件,有多少StudentCourse记录符合course\u id=这是一个3比1的场景。计数包含的内容是课程的3倍。对于每个课程id,它可能匹配50-100名学生。这些反过来与计数表中50名学生的课程返回次数相匹配。每个学生与另一个学生一起上课时,返回的单词组合最多为500个。您能否更具体地说明表格和结果集的大小?如果StudentCourse表相当小,我想知道为什么不使用它进行扫描。
SELECT *
FROM StudentCourseCount sc INNER JOIN
     StudentCourse s1
     ON s1.course_id = <id> AND sc.student1_id = s1.student_id INNER JOIN
     StudentCourse s2
     ON s2.course_id = <id> AND sc.student2_id = s2.student_id
WHERE sc.course_count > 1;