0

我遇到了一个奇怪的问题,需要一些帮助来确定原因。到目前为止,我只能观察到症状。它“似乎”正在发生的是 MySQL 正在执行不同的查询,具体取决于我在第一次“LEFT JOIN”之前是否有换行符。

这是我的设置:

我正在对 www.xeround.com 提供的 MySQL 数据库实例运行查询。我正在使用 Kohana 框架,版本 3.0。我在 Lighttpd 上运行 PHP 5.3.3 FastCGI。我用 MySQL Native Driver 编译了 PHP:

--with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd

我正在使用默认的 Kohana 3 MySQL 数据库驱动程序和 QueryBuilder。

我将跳过 PHP 代码并分享 SQL,因为这似乎是问题所在。QueryBuilder 最终构建了这个查询:

SELECT `fieldreps`.`user_id` AS `fieldreps.user_id`, `fieldreps`.`availability_id` AS `fieldreps.availability_id`, `fieldreps`.`applicant_type` AS `fieldreps.applicant_type`, `fieldreps`.`license_number` AS `fieldreps.license_number`, `fieldreps`.`license_exp` AS `fieldreps.license_exp`, `fieldreps`.`license_state` AS `fieldreps.license_state`, `fieldreps`.`car` AS `fieldreps.car`, `fieldreps`.`authorized_worker` AS `fieldreps.authorized_worker`, `fieldreps`.`restrictions` AS `fieldreps.restrictions`, `fieldreps`.`night` AS `fieldreps.night`, `fieldreps`.`day` AS `fieldreps.day`, `fieldreps`.`longer` AS `fieldreps.longer`, `fieldreps`.`commitment` AS `fieldreps.commitment`, `fieldreps`.`travel_metro` AS `fieldreps.travel_metro`, `fieldreps`.`travel_states` AS `fieldreps.travel_states`, `fieldreps`.`big_employee` AS `fieldreps.big_employee`, `fieldreps`.`employed` AS `fieldreps.employed`, `fieldreps`.`retail` AS `fieldreps.retail`, `fieldreps`.`status` AS `fieldreps.status`, `fieldreps`.`start` AS `fieldreps.start`, `fieldreps`.`sales` AS `fieldreps.sales`, `fieldreps`.`study` AS `fieldreps.study`, `fieldreps`.`relevant` AS `fieldreps.relevant`, `fieldreps`.`experience` AS `fieldreps.experience`, `fieldreps`.`claims` AS `fieldreps.claims`, `fieldreps`.`education` AS `fieldreps.education`, `fieldreps`.`degree_details` AS `fieldreps.degree_details`, `fieldreps`.`degree_institution` AS `fieldreps.degree_institution`, `fieldreps`.`other_training` AS `fieldreps.other_training`, `fieldreps`.`jobs` AS `fieldreps.jobs`, `fieldreps`.`current_training` AS `fieldreps.current_training`, `fieldreps`.`interested` AS `fieldreps.interested`, `fieldreps`.`achievements` AS `fieldreps.achievements`, `fieldreps`.`passions` AS `fieldreps.passions`, `fieldreps`.`ambitions` AS `fieldreps.ambitions`, `fieldreps`.`max_travel_time` AS `fieldreps.max_travel_time`, `fieldreps`.`creation_time` AS `fieldreps.creation_time`, `fieldreps`.`resume` AS `fieldreps.resume`, `users`.`user_id` AS `users.user_id`, `users`.`email` AS `users.email`, `users`.`name` AS `users.name`, `users`.`password` AS `users.password`, `users`.`given_name` AS `users.given_name`, `users`.`title` AS `users.title`, `users`.`nationality` AS `users.nationality`, `availabilities`.`availability_id` AS `availabilities.availability_id`, `availabilities`.`fieldrep_id` AS `availabilities.fieldrep_id`, `availabilities`.`mon_start` AS `availabilities.mon_start`, `availabilities`.`mon_end` AS `availabilities.mon_end`, `availabilities`.`tue_start` AS `availabilities.tue_start`, `availabilities`.`tue_end` AS `availabilities.tue_end`, `availabilities`.`wed_start` AS `availabilities.wed_start`, `availabilities`.`wed_end` AS `availabilities.wed_end`, `availabilities`.`thur_start` AS `availabilities.thur_start`, `availabilities`.`thur_end` AS `availabilities.thur_end`, `availabilities`.`fri_start` AS `availabilities.fri_start`, `availabilities`.`fri_end` AS `availabilities.fri_end`, `availabilities`.`sat_start` AS `availabilities.sat_start`, `availabilities`.`sat_end` AS `availabilities.sat_end`, `availabilities`.`sun_start` AS `availabilities.sun_start`, `availabilities`.`sun_end` AS `availabilities.sun_end` FROM `fieldreps` AS `fieldreps` LEFT JOIN `users` ON (`fieldreps`.`user_id` = `users`.`user_id`) LEFT JOIN `availabilities` ON (`fieldreps`.`availability_id` = `availabilities`.`availability_id`)

它返回这样的结果:(我删除了从 Fieldreps 表返回的大部分字段,以使其简短且不那么个性化。)

[0] => Array
    (
        [fieldreps.user_id] => 1f01f4c2-43fd-550d-a53d-1f191786ebad
        [fieldreps.availability_id] => e31b0773-ecba-41d1-8ebb-7ac718496456
        [fieldreps.car] => Yes
        [fieldreps.authorized_worker] => Yes
        [fieldreps.restrictions] => Has Restrictions: No 
        [fieldreps.night] => Yes
        [fieldreps.day] => Yes
        [fieldreps.longer] => Yes
        [users.user_id] => 1f01f4c2-43fd-550d-a53d-1f191786ebad
        [users.email] => dsfsdfsdfsdfsdfs@sdfsdfsdfsdfsd.com
        [users.name] => Jones
        [users.password] =>
        [users.given_name] => Fred
        [users.title] => Miss
        [users.nationality] => 
        [availabilities.availability_id] => 
        [availabilities.fieldrep_id] => 
        [availabilities.mon_start] => 
        [availabilities.mon_end] => 
        [availabilities.tue_start] => 
        [availabilities.tue_end] => 
        [availabilities.wed_start] => 
        [availabilities.wed_end] => 
        [availabilities.thur_start] => 
        [availabilities.thur_end] => 
        [availabilities.fri_start] => 
        [availabilities.fri_end] => 
        [availabilities.sat_start] => 
        [availabilities.sat_end] => 
        [availabilities.sun_start] => 
        [availabilities.sun_end] => 
    )
[1] => Array
    (
        [fieldreps.user_id] => 812c3a9f-d7d8-565a-a886-1b182753dd41
        [fieldreps.availability_id] => 
        [fieldreps.car] => 1
        [fieldreps.authorized_worker] => 1
        [fieldreps.restrictions] => 
        [fieldreps.night] => 1
        [fieldreps.day] => 1
        [fieldreps.longer] => 1
        [users.user_id] => 812c3a9f-d7d8-565a-a886-1b182753dd41
        [users.email] => sdfsdfsdfsdfsdf@sdfsdfsdfsdf.com
        [users.name] => Smith
        [users.password] => 
        [users.given_name] => Jill 
        [users.title] => 
        [users.nationality] => 
        [availabilities.availability_id] => 
        [availabilities.fieldrep_id] => 
        [availabilities.mon_start] => 
        [availabilities.mon_end] => 
        [availabilities.tue_start] => 
        [availabilities.tue_end] => 
        [availabilities.wed_start] => 
        [availabilities.wed_end] => 
        [availabilities.thur_start] => 
        [availabilities.thur_end] => 
        [availabilities.fri_start] => 
        [availabilities.fri_end] => 
        [availabilities.sat_start] => 
        [availabilities.sat_end] => 
        [availabilities.sun_start] => 
        [availabilities.sun_end] => 

但是,当我在第一个 LEFT JOIN 之前立即插入换行符时,如下所示:

SELECT `fieldreps`.`user_id` AS `fieldreps.user_id`, `fieldreps`.`availability_id` AS `fieldreps.availability_id`, `fieldreps`.`applicant_type` AS `fieldreps.applicant_type`, `fieldreps`.`license_number` AS `fieldreps.license_number`, `fieldreps`.`license_exp` AS `fieldreps.license_exp`, `fieldreps`.`license_state` AS `fieldreps.license_state`, `fieldreps`.`car` AS `fieldreps.car`, `fieldreps`.`authorized_worker` AS `fieldreps.authorized_worker`, `fieldreps`.`restrictions` AS `fieldreps.restrictions`, `fieldreps`.`night` AS `fieldreps.night`, `fieldreps`.`day` AS `fieldreps.day`, `fieldreps`.`longer` AS `fieldreps.longer`, `fieldreps`.`commitment` AS `fieldreps.commitment`, `fieldreps`.`travel_metro` AS `fieldreps.travel_metro`, `fieldreps`.`travel_states` AS `fieldreps.travel_states`, `fieldreps`.`big_employee` AS `fieldreps.big_employee`, `fieldreps`.`employed` AS `fieldreps.employed`, `fieldreps`.`retail` AS `fieldreps.retail`, `fieldreps`.`status` AS `fieldreps.status`, `fieldreps`.`start` AS `fieldreps.start`, `fieldreps`.`sales` AS `fieldreps.sales`, `fieldreps`.`study` AS `fieldreps.study`, `fieldreps`.`relevant` AS `fieldreps.relevant`, `fieldreps`.`experience` AS `fieldreps.experience`, `fieldreps`.`claims` AS `fieldreps.claims`, `fieldreps`.`education` AS `fieldreps.education`, `fieldreps`.`degree_details` AS `fieldreps.degree_details`, `fieldreps`.`degree_institution` AS `fieldreps.degree_institution`, `fieldreps`.`other_training` AS `fieldreps.other_training`, `fieldreps`.`jobs` AS `fieldreps.jobs`, `fieldreps`.`current_training` AS `fieldreps.current_training`, `fieldreps`.`interested` AS `fieldreps.interested`, `fieldreps`.`achievements` AS `fieldreps.achievements`, `fieldreps`.`passions` AS `fieldreps.passions`, `fieldreps`.`ambitions` AS `fieldreps.ambitions`, `fieldreps`.`max_travel_time` AS `fieldreps.max_travel_time`, `fieldreps`.`creation_time` AS `fieldreps.creation_time`, `fieldreps`.`resume` AS `fieldreps.resume`, `users`.`user_id` AS `users.user_id`, `users`.`email` AS `users.email`, `users`.`name` AS `users.name`, `users`.`password` AS `users.password`, `users`.`given_name` AS `users.given_name`, `users`.`title` AS `users.title`, `users`.`nationality` AS `users.nationality`, `availabilities`.`availability_id` AS `availabilities.availability_id`, `availabilities`.`fieldrep_id` AS `availabilities.fieldrep_id`, `availabilities`.`mon_start` AS `availabilities.mon_start`, `availabilities`.`mon_end` AS `availabilities.mon_end`, `availabilities`.`tue_start` AS `availabilities.tue_start`, `availabilities`.`tue_end` AS `availabilities.tue_end`, `availabilities`.`wed_start` AS `availabilities.wed_start`, `availabilities`.`wed_end` AS `availabilities.wed_end`, `availabilities`.`thur_start` AS `availabilities.thur_start`, `availabilities`.`thur_end` AS `availabilities.thur_end`, `availabilities`.`fri_start` AS `availabilities.fri_start`, `availabilities`.`fri_end` AS `availabilities.fri_end`, `availabilities`.`sat_start` AS `availabilities.sat_start`, `availabilities`.`sat_end` AS `availabilities.sat_end`, `availabilities`.`sun_start` AS `availabilities.sun_start`, `availabilities`.`sun_end` AS `availabilities.sun_end` FROM `fieldreps` AS `fieldreps` 
LEFT JOIN `users` ON (`fieldreps`.`user_id` = `users`.`user_id`) LEFT JOIN `availabilities` ON (`fieldreps`.`availability_id` = `availabilities`.`availability_id`)

我现在得到了我想要的结果:

[0] => Array
    (
        [fieldreps.user_id] => 1f01f4c2-43fd-550d-a53d-1f191786ebad
        [fieldreps.availability_id] => e31b0773-ecba-41d1-8ebb-7ac718496456
        [fieldreps.car] => Yes
        [fieldreps.authorized_worker] => Yes
        [fieldreps.restrictions] => Has Restrictions: No 
        [fieldreps.night] => Yes
        [fieldreps.day] => Yes
        [fieldreps.longer] => Yes
        [users.user_id] => 1f01f4c2-43fd-550d-a53d-1f191786ebad
        [users.email] => dsfsdfsdfsdfsdfs@sdfsdfsdfsdfsd.com
        [users.name] => Jones
        [users.password] =>
        [users.given_name] => Fred
        [users.title] => Miss
        [users.nationality] => 
        [availabilities.availability_id] => e31b0773-ecba-41d1-8ebb-7ac718496456
        [availabilities.fieldrep_id] => 1f01f4c2-43fd-550d-a53d-1f191786ebad
        [availabilities.mon_start] => 540
        [availabilities.mon_end] => 1020
        [availabilities.tue_start] => 540
        [availabilities.tue_end] => 1020
        [availabilities.wed_start] => 540
        [availabilities.wed_end] => 1020
        [availabilities.thur_start] => 540
        [availabilities.thur_end] => 1020
        [availabilities.fri_start] => 540
        [availabilities.fri_end] => 1020
        [availabilities.sat_start] => 
        [availabilities.sat_end] => 
        [availabilities.sun_start] => 
        [availabilities.sun_end] => 
    )
[1] => Array
    (
        [fieldreps.user_id] => 812c3a9f-d7d8-565a-a886-1b182753dd41
        [fieldreps.availability_id] => 
        [fieldreps.car] => 1
        [fieldreps.authorized_worker] => 1
        [fieldreps.restrictions] => 
        [fieldreps.night] => 1
        [fieldreps.day] => 1
        [fieldreps.longer] => 1
        [users.user_id] => 812c3a9f-d7d8-565a-a886-1b182753dd41
        [users.email] => sdfsdfsdfsdfsdf@sdfsdfsdfsdf.com
        [users.name] => Smith
        [users.password] => 
        [users.given_name] => Jill 
        [users.title] => 
        [users.nationality] => 
        [availabilities.availability_id] => 
        [availabilities.fieldrep_id] => 
        [availabilities.mon_start] => 
        [availabilities.mon_end] => 
        [availabilities.tue_start] => 
        [availabilities.tue_end] => 
        [availabilities.wed_start] => 
        [availabilities.wed_end] => 
        [availabilities.thur_start] => 
        [availabilities.thur_end] => 
        [availabilities.fri_start] => 
        [availabilities.fri_end] => 
        [availabilities.sat_start] => 
        [availabilities.sat_end] => 
        [availabilities.sun_start] => 
        [availabilities.sun_end] => 

请注意,Users 表上的 LEFT JOIN 在这两种情况下都可以正常工作。我还尝试在第二个 LEFT JOIN 之前添加换行符,而不是第一个。同样不想要的结果。我能找到的唯一解决方法是在第一个 LEFT JOIN 前面放置一个换行符。由 QueryBuilder 构建并发送到 MySQL 的查询总是长的、单行的、最小的空白字符串……没有换行符!这是我第一次遇到这个问题。我简直不敢相信在第一个 LEFT JOIN 之前需要放置一个换行符。

我的问题归结为以下几点:

  1. 这应该以这种方式发生吗?(影响查询结果的空格)
  2. 获得我想要的结果的最佳方法是什么。

我不是 SQL 专家,否则我可能不需要问这个问题。我确信我忽略了一些东西。

谢谢,

乔纳森

4

1 回答 1

0

我的问题就在我面前,就像我想的那样:

指数

我无意中在availability.fieldrep_id 上创建了两个索引,而架构其余部分的索引充其量只是粗制滥造。

我使用了 EXPLAIN,这表明它没有为三个连接中的两个使用索引。我清理了我的索引,现在它每次都很好用。

另外,我想我知道为什么换行符会改变查询。如果我一遍又一遍地运行查询,我会看到它在给出的示例之间切换,无论是否添加换行符。我假设 MySQL 对重复查询有一些缓存。我敢打赌,换行符足以触发它忽略缓存的版本,因此它有时会给我想要的结果。

无论如何,问题在于索引。其他一切都只是一个症状。

也许这会帮助某人节省一些时间。

于 2011-12-29T23:18:50.140 回答