【问题标题】:Table and Query optimization表和查询优化
【发布时间】:2015-03-09 16:28:46
【问题描述】:

简单的网络应用,托管在使用 PHP 和 MySql 后端的标准共享主机上。

我有两个相对较小的表(每个表几百行),当我使用连接查询时,查询可能需要两到三秒。

这是一张桌子:'students':

CREATE TABLE IF NOT EXISTS `students` (
`_id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `firstname` char(30) NOT NULL,
  `lastname` char(30) NOT NULL,
  `dateOfBirth` date DEFAULT NULL,
  `gender` varchar(10) NOT NULL,
  `knownasname` varchar(30) NOT NULL,
  `school` varchar(30) DEFAULT NULL,
  `schoolyear` varchar(30) DEFAULT NULL,
  `notes` text,
  `foundusvia` varchar(30) DEFAULT NULL,
  `dateadded` datetime NOT NULL,
  `archived` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`_id`),
  UNIQUE KEY `_id` (`_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=684 ;

这是第二个:

CREATE TABLE IF NOT EXISTS `contacts` (
  `_id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `student_id` mediumint(9) NOT NULL,
  `studentAddressStreet` varchar(50) DEFAULT NULL,
  `studentAddressArea` varchar(30) DEFAULT NULL,
  `studentAddressTown` varchar(30) DEFAULT NULL,
  `studentAddressPostcode` varchar(30) DEFAULT NULL,
  `studentPhoneMobile` varchar(30) DEFAULT NULL,
  `studentPhoneLand` varchar(30) DEFAULT NULL,
  `studentAddressNotes` text,
  `studentemail` varchar(50) DEFAULT NULL,
  `billingAddressStreet` varchar(50) DEFAULT NULL,
  `billingAddressArea` varchar(30) DEFAULT NULL,
  `billingAddressTown` varchar(30) DEFAULT NULL,
  `billingAddressPostcode` varchar(30) DEFAULT NULL,
  `billingPhoneMobile` varchar(30) DEFAULT NULL,
  `billingPhoneLand` varchar(30) DEFAULT NULL,
  `billingContactName` varchar(30) DEFAULT NULL,
  `billingContactRelationship` varchar(30) DEFAULT NULL,
  `billingAddressNotes` text,
  `billingemail` varchar(50) DEFAULT NULL,
  `caregiverAddressStreet` varchar(50) DEFAULT NULL,
  `caregiverAddressArea` varchar(30) DEFAULT NULL,
  `caregiverAddressTown` varchar(30) DEFAULT NULL,
  `caregiverAddressPostcode` varchar(30) DEFAULT NULL,
  `caregiverPhoneMobile` varchar(30) DEFAULT NULL,
  `caregiverPhoneLand` varchar(30) DEFAULT NULL,
  `caregiverContactName` varchar(30) DEFAULT NULL,
  `caregiverContactRelationship` varchar(30) DEFAULT NULL,
  `caregiverAddressNotes` text,
  `caregiveremail` varchar(50) DEFAULT NULL,
    PRIMARY KEY (`_id`),
  KEY `contacts_index` (`student_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=290 ;

这是查询:

它的工作是从表“students”和“contacts”中为具有给定_id的学生获取所有数据。

SELECT * 
  FROM students, contacts
 WHERE students._id = contacts.student_id
  AND students._id =99  <=== This value obviously changes

contacts 在student_id 上有一个索引

学生表有一个关于名字和姓氏的索引。

让这个查询需要 2 到 3 秒才能运行有什么问题?表很小,查询很简单。非常感谢任何帮助!

编辑:这是 EXPLAIN 的输出。还修改了联系人表的 CREATE

id | select_type | table   | type | possible_keys | key          | key_len | ref  | rows | Extra
===|=============|=========|======|===============|==============|=========|======|=============
1  |  SIMPLE     | students|const | PRIMARY       | PRIMARY      |  3      |const | 1    |
1  |  SIMPLE     | contacts|ref   | contacts_index|contacts_index|  3      |const | 1    |

【问题讨论】:

  • contacts 表中在(student_id) 上创建索引。
  • 另外加上EXPLAIN。顺便说一句 UNIQUE KEY _id` (_id)` 是多余的
  • 只选择你想要的列。使用正确的 JOIN 语法加入。并在contacts.student_id上放置一个索引
  • @zerkms 我怀疑这些东西是由应用程序生成的。
  • 您说“contacts 在 student_id 上有一个索引”,但它没有显示在您的 CREATE TABLE 语句中。

标签: mysql select optimization


【解决方案1】:

专业提示:尽可能避免使用SELECT *。在 JOIN 上尤其成问题。

如果您像这样使用标准 JOIN,您将更轻松地阅读查询。在 1990 年代后期的某个时间,以逗号分隔的表格列表 jumped the shark

SELECT students.*, 
       contacts.* 
  FROM students
  LEFT JOIN contacts ON students._id = contacts.student_id
 WHERE students._id =99 

最后,在contacts 表的student_id 列上放置一个索引,以便连接可以快速访问该表。

【讨论】:

  • 谢谢。我有点需要所有列,因此需要“select *”。将尝试加入。在contacts.student_id 上已经有一个索引(见我上面的评论)。
  • @marknz 看到两个表共享一列,这不可能是真的!
猜你喜欢
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
  • 2017-12-25
相关资源
最近更新 更多