我目前正在开发一个应用程序,允许用户使用各种参数搜索文档数据库并返回一组分页结果。我在PHP / MySQL中构建它,这不是我通常的开发平台,但它到目前为止一直很盛大。
我遇到的问题是,为了返回一整套结果,我必须在每张桌子上使用LEFT JOIN,这完全破坏了我的表现。开发数据库的人说我正在使用的查询将返回正确的结果,这就是我必须使用的。查询如下,我绝不是SQL大师,可以使用一些帮助。
我一直在想将查询拆分成子查询可能会更好吗?以下是我目前的疑问:
SELECT d.title, d.deposition_id, d.folio_start, d.folio_end, pl.place_id, p.surname, p.forename, p.person_type_id, pt.person_type_desc, p.age, d.manuscript_number, dt.day, dt.month, dt.year, plc.county_id, c.county_desc
FROM deposition d
LEFT JOIN person AS p ON p.deposition_id = d.deposition_id
LEFT JOIN person_type AS pt ON p.person_type_id = pt.person_type_id
LEFT JOIN place_link AS pl ON pl.deposition_id = d.deposition_id
LEFT JOIN date AS dt ON dt.deposition_id = d.deposition_id
LEFT JOIN place AS plc ON pl.place_id = plc.place_id
LEFT JOIN county AS c ON plc.county_id = c.county_id
WHERE 1 AND d.manuscript_number = '840'
GROUP BY d.deposition_id ORDER BY d.folio_start ASC
LIMIT 0, 20
非常感谢任何帮助或指导!
沉积表:
CREATE TABLE IF NOT EXISTS `deposition` (
`deposition_id` varchar(11) NOT NULL default '',
`manuscript_number` int(10) NOT NULL default '0',
`folio_start` varchar(4) NOT NULL default '0',
`folio_end` varchar(4) default '0',
`page` int(4) default NULL,
`deposition_type_id` int(10) NOT NULL default '0',
`comments` varchar(255) default '',
`title` varchar(255) default NULL,
PRIMARY KEY (`deposition_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
日期表
CREATE TABLE IF NOT EXISTS `date` (
`deposition_id` varchar(11) NOT NULL default '',
`day` int(2) default NULL,
`month` int(2) default NULL,
`year` int(4) default NULL,
PRIMARY KEY (`deposition_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Person_Type
CREATE TABLE IF NOT EXISTS `person_type` (
`person_type_id` int(10) NOT NULL auto_increment,
`person_type_desc` varchar(255) NOT NULL default '',
PRIMARY KEY (`person_type_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=59 ;
答案 0 :(得分:2)
似乎您希望每次沉积时选择一个人,地点等。
您编写的查询将返回给您,但不保证它将返回哪一个,并且查询效率低下。
试试这个:
SELECT d.title, d.deposition_id, d.folio_start, d.folio_end, pl.place_id, p.surname, p.forename, p.person_type_id, pt.person_type_desc, p.age, d.manuscript_number, dt.day, dt.month, dt.year, plc.county_id, c.county_desc
FROM deposition d
LEFT JOIN
person p
ON p.id =
(
SELECT id
FROM person pi
WHERE pi.deposition_id = d.deposition_id
ORDER BY
pi.deposition_id, pi.id
LIMIT 1
)
LEFT JOIN
place_link AS pl
ON pl.id =
(
SELECT id
FROM place_link AS pli
WHERE pli.deposition_id = d.deposition_id
ORDER BY
pli.deposition_id, pi.id
LIMIT 1
)
LEFT JOIN
date AS dt
ON dt.id =
(
SELECT id
FROM date AS dti
WHERE dti.deposition_id = d.deposition_id
ORDER BY
dti.deposition_id, pi.id
LIMIT 1
)
LEFT JOIN
place AS plc
ON plc.place_id = pl.place_id
LEFT JOIN
county AS c
ON c.county_id = plc.county_id
WHERE d.manuscript_number = '840'
ORDER BY
d.manuscript_number, d.folio_start
LIMIT 20
在deposition (manuscript_number, folio_start)
上创建一个索引,以便快速工作
还在(deposition_id, id)
,person
和place_link
上的date
上创建综合索引。
答案 1 :(得分:1)
如果连接的表可能没有匹配的值,则只需要LEFT JOIN
。您的数据库架构中person
是否可能没有匹配的person_type
?或deposition
在date
中没有匹配的行? place
没有匹配的county
?
对于结果有意义的任何关系,您可以将LEFT JOIN
更改为INNER JOIN
。
这些列应具有索引(如果可能,则为唯一):
person.deposition_id
date.deposition_id
place_link.deposition_id
place_link.place_id
date
表看起来像一个糟糕的设计;我想不出有一个日期表的原因,而不是只在date
表中放置datetime
(或deposition
)类型的列。并且date
是表的可怕名称,因为它是SQL保留字。
答案 2 :(得分:1)
糟糕的表现几乎可以肯定是缺乏指数。您的存款表没有任何索引,这可能意味着您引用的其他表也没有任何索引。您可以首先在沉积表中添加索引。从MySQL shell或phpMyAdmin发出以下查询。
ALTER TABLE沉积ADD INDEX(deposition_id,manuscript_number);
如果在添加索引后查询执行得更快,您就知道自己处于正确的轨道上。从那里,您可能希望将索引放在引用列上的其他表上。例如,对于这部分查询“LEFT JOIN person AS p ON p.deposition_id = d.deposition_id”,您可以尝试使用。添加索引到人员表。
ALTER TABLE person ADD INDEX(deposition_id);