2014-03-27 55 views
0

大家好我有一个MySQL查询从多个表中提取数据。这里是我的查询MySQL查询优化改进

SELECT 
       user_id as id, 
       user_name as name, 
       user_phone as phone, 
       user_email as email, 
       user_address1 as address1, 
       user_address2 as address2, 
       user_city as city, 
       user_state as state, 
       user_country as country, 
       user_available as available, 
       user_location as location, 
       user_latitude as latitude, 
       user_longitude as longitude, 
       user_description as description, 
       user_company as company, 
       user_gender as gender, 
       (SELECT MIN(service_price) FROM service WHERE service.user_id = a.user_id) as price, 
       (SELECT service_recomanded FROM service WHERE service.user_id = a.user_id ORDER BY service.service_price ASC LIMIT 1) as recomandad, 
       verified_email, 
       verified_facebook, 
       verified_phone, 
       verified_twitter, 
       (SELECT providerphoto_name FROM providerphoto WHERE providerphoto.user_id = a.user_id ORDER BY providerphoto_order ASC LIMIT 1) as photo, 
       (SELECT ROUND(AVG(review_rate),2) FROM review WHERE review.user_id = a.user_id) AS rate, 
       (SELECT service_ICOC FROM service WHERE service.user_id = a.user_id ORDER BY service_price ASC LIMIT 1) as type 
      FROM 
       user a 
      WHERE a.user_type = 'provider' 
       AND a.user_active=1 
       AND a.user_deleted=0 

它从用户表,服务表,评论表和供应商图片表中获取数据。它也可以工作,但执行时间非常缓慢。我想让它成为一个单一的查询,并避免内部的五个查询可能运行得很快。任何帮助?

表结构。

-- 
-- Table structure for table `providerphoto` 
-- 

CREATE TABLE IF NOT EXISTS `providerphoto` (
    `providerphoto_id` int(11) NOT NULL AUTO_INCREMENT, 
    `user_id` int(11) NOT NULL, 
    `providerphoto_file` varchar(256) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
    `providerphoto_name` varchar(256) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
    `providerphoto_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `providerphoto_order` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`providerphoto_id`), 
    KEY `user_id` (`user_id`), 
    KEY `providerphoto` (`user_id`,`providerphoto_name`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=487 ; 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `review` 
-- 

CREATE TABLE IF NOT EXISTS `review` (
    `review_id` int(11) NOT NULL AUTO_INCREMENT, 
    `review_title` varchar(256) COLLATE utf8_unicode_ci NOT NULL, 
    `user_id` int(11) NOT NULL, 
    `review_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `review_content` text COLLATE utf8_unicode_ci NOT NULL, 
    `review_user_id` int(11) NOT NULL, 
    `review_rate` int(10) NOT NULL DEFAULT '1', 
    `review_tip` int(11) NOT NULL DEFAULT '0', 
    `service_booked` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`review_id`), 
    KEY `user_id` (`user_id`), 
    KEY `review_date` (`review_date`), 
    KEY `review_user_id` (`review_user_id`), 
    KEY `review_rate` (`review_rate`), 
    KEY `review_tip` (`review_tip`), 
    KEY `service_booked` (`service_booked`), 
    KEY `review` (`user_id`,`review_rate`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=97 ; 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `service` 
-- 

CREATE TABLE IF NOT EXISTS `service` (
    `service_id` int(11) NOT NULL AUTO_INCREMENT, 
    `service_name` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `user_id` int(11) DEFAULT NULL, 
    `service_created_by` int(11) NOT NULL DEFAULT '0', 
    `service_ICOC` varchar(256) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
    `service_price` int(11) NOT NULL, 
    `service_date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `service_date_expire` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `service_time` varchar(256) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `service_rate` varchar(256) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `service_type` int(10) NOT NULL DEFAULT '1' COMMENT '1-in call, 2-out call, 3-in&out call', 
    `service_recomanded` int(2) NOT NULL DEFAULT '0', 
    `service_genre` varchar(100) COLLATE utf8_unicode_ci NOT NULL, 
    `service_message` text COLLATE utf8_unicode_ci NOT NULL, 
    PRIMARY KEY (`service_id`), 
    KEY `user_id` (`user_id`), 
    KEY `service_ICOC` (`service_ICOC`(255)), 
    KEY `service` (`user_id`,`service_price`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=854 ; 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `user` 
-- 

CREATE TABLE IF NOT EXISTS `user` (
    `user_id` int(11) NOT NULL AUTO_INCREMENT, 
    `user_name` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `user_password` varchar(256) COLLATE utf8_unicode_ci NOT NULL, 
    `user_email` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `user_phone` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `user_address1` text COLLATE utf8_unicode_ci, 
    `user_address2` text COLLATE utf8_unicode_ci NOT NULL, 
    `user_city` varchar(256) COLLATE utf8_unicode_ci NOT NULL, 
    `user_state` varchar(256) COLLATE utf8_unicode_ci NOT NULL, 
    `user_country` varchar(256) COLLATE utf8_unicode_ci NOT NULL, 
    `user_company` varchar(256) COLLATE utf8_unicode_ci NOT NULL, 
    `user_birthday` date DEFAULT NULL, 
    `user_register_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 
    `user_type` enum('provider','client') COLLATE utf8_unicode_ci DEFAULT NULL, 
    `user_description` text COLLATE utf8_unicode_ci NOT NULL, 
    `user_available` int(10) NOT NULL DEFAULT '1', 
    `verified_email` tinyint(1) NOT NULL DEFAULT '0', 
    `verified_facebook` tinyint(1) NOT NULL DEFAULT '0', 
    `verified_phone` tinyint(1) NOT NULL DEFAULT '0', 
    `verified_twitter` tinyint(1) NOT NULL DEFAULT '0', 
    `user_facebook_friends` int(11) NOT NULL DEFAULT '0', 
    `user_twitter_friends` int(11) NOT NULL DEFAULT '0', 
    `user_longitude` decimal(10,5) NOT NULL DEFAULT '0.00000', 
    `user_latitude` decimal(10,5) NOT NULL DEFAULT '0.00000', 
    `user_deleted` tinyint(4) NOT NULL DEFAULT '0', 
    `user_gender` int(11) NOT NULL DEFAULT '0', 
    `user_facebook_token` varchar(200) COLLATE utf8_unicode_ci NOT NULL, 
    `user_active` tinyint(4) NOT NULL DEFAULT '1', 
    `user_location` varchar(200) COLLATE utf8_unicode_ci NOT NULL, 
    `user_push_notification_token` varchar(100) COLLATE utf8_unicode_ci NOT NULL, 
    `user_timezone_diff` int(11) NOT NULL DEFAULT '0', 
    `balanced_uri` text COLLATE utf8_unicode_ci NOT NULL, 
    `user_reset_passwd_token` varchar(200) COLLATE utf8_unicode_ci NOT NULL, 
    `is_test_user` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`user_id`), 
    KEY `deleted_idx` (`user_deleted`), 
    KEY `email_idx` (`user_email`(255)) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=426 ; 
+1

如果您希望我们帮助优化查询,您需要向我们展示表格和索引定义**以及每个表格的行数。也许你的表格定义不好。也许索引没有正确创建。也许你没有一个你认为你做过的那个专栏的索引。没有看到表和索引定义,我们不能说。我们还需要行计数,因为这会大大影响查询优化。如果你知道如何做一个'EXPLAIN'或者得到一个执行计划,那就把结果也放在问题中。如果您没有索引,请尽快访问http://use-the-index-luke.com。 –

+0

您是否尝试在这些表中使用'LEFT JOIN'而不是在SELECT中添加子查询?还提供表格中索引和记录数量的详细信息。 – Slowcoder

+0

@AndyLester这个查询得到结果,所以第一件事就是确定表中有索引,第二件事是用户表中的行数是321,查看表115服务表723提供者图片表239,并且这些表中的每一个都有user_id作为与用户表关联的外键。 –

回答

1

您可能只需添加索引即可加快查询速度。尝试添加以下指标:

service(user_id, service_price) 
providerphoto(user_id, providerphoto_order) 
review(user_id, review_rate) 
+0

我改变了表格并添加了这些索引,但它不起作用。 –

+0

@devdesign。 。 。我觉得很惊讶。我将注释掉五个子查询,然后将它们一次添加到一个子查询中,以确定性能问题发生的位置。 –

0

我会做的第一件事是指数user.user_typeuser.user_deleteduser.user_active让优化器迅速用较小的一套user记录开始不得不应对。

是否允许service.user_id为NULL?这似乎是一个错误。

另外,你可能想要在你正在做ORDER BY的任何列上抛出索引。

找出此查询中速度较慢的最佳方法是进行EXPLAIN QUERY并分析它告诉您的内容。我们也可以帮助你。

+0

没有service.user_id不能为空。你能否写出你认为最好的查询? –

+0

找出此查询中速度缓慢的最佳方法是执行EXPLAIN QUERY并分析它告诉您的内容。我们也可以帮助你。 –

1

就是这样。这将返回用户的所有值,因为我在查询中没有使用ORDERLIMIT。这只是为了方法。

SELECT 
      a.user_id as id, 
      user_name as name, 
      user_phone as phone, 
      user_email as email, 
      user_address1 as address1, 
      user_address2 as address2, 
      user_city as city, 
      user_state as state, 
      user_country as country, 
      user_available as available, 
      user_location as location, 
      user_latitude as latitude, 
      user_longitude as longitude, 
      user_description as description, 
      user_company as company, 
      user_gender as gender, 
      MIN(s.service_price) as price, 
      s.service_recomanded as recomandad, 
      verified_email, 
      verified_facebook, 
      verified_phone, 
      verified_twitter, 
      pp.providerphoto_name as photo, 
      ROUND(AVG(r.review_rate),2) as rate, 
      s.service_ICOC as type 
     FROM 
      user a LEFT JOIN service s on s.user_id = a.user_id LEFT JOIN providerphoto pp on pp.user_id = a.user_id LEFT JOIN review r on r.user_id = a.user_id 
     WHERE a.user_type = 'provider' 
      AND a.user_active=1 
      AND a.user_deleted=0; 
+0

这只返回一行。但是,如果从字段中删除MIN和ROUND(AVG),它将返回200条记录,并且比使用内部SELECT查询的原始查询的速度更快,但由于原始查询返回的查询是正确的,因此记录缺少38行。 –