Получить данные из MySQL, занимая почти 436 секунд - PullRequest
0 голосов
/ 24 октября 2018

Я разработчик Android и не имею большого опыта в MySQL.У меня есть 3 таблицы в базе данных mysql.

Первая таблица: - UserTable

+-------------+-------------+----------+----------------------+
| user_id     | name      |   image    |   joining_date       |
+-------------+-------------+----------+----------------------+
|         100 | King      | defualt.jpg | 2018-05-23 20:09:27 |
|         101 | Kochhar   | defualt.jpg | 2018-05-23 20:09:27 |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |

Вторая таблица: - friendRequests

+-------------+-------------+----------+
| unique_id   | from_id     |   to_id  |
+-------------+-------------+----------+
|         1  | 100          | 101      |
|         2  | 200          | 110      |
| - - - - - - - - - - - - - - - - - - -|
| - - - - - - - - - - - - - - - - - - -|

Третий стол: - друзья

+-------------+-------------+----------+
| unique_id   | from_id     |   to_id  |
+-------------+-------------+----------+
|         1  | 104          | 101      |
|         2  | 206          | 110      |
| - - - - - - - - - - - - - - - - - - -|
| - - - - - - - - - - - - - - - - - - -|

Я хочу получить список пользователей, которые не являются моими друзьями, а также мы не ожидаем запроса на добавление в друзья.Поэтому я попытался с помощью следующего запроса: -

SELECT usertable.name,
       usertable.user_id,
       usertable.image
FROM   `UserTable` AS usertable
WHERE  usertable.user_id <> '100'
       AND (SELECT Count(*)
            FROM   friendrequests
            WHERE  ( to_id = '100'
                     AND from_id = usertable.user_id )
                    OR ( to_id = usertable.user_id
                         AND from_id = '100' )) = 0
       AND (SELECT Count(*)
            FROM   friends
            WHERE  to_id = usertable.user_id
                   AND from_id = '100'
                    OR to_id = '100'
                       AND from_id = usertable.user_id) = 0
ORDER  BY usertable.joining_date DESC
LIMIT  10  

Это работает, но занимает 436 секунд.Как правильно написать этот запрос?

1 Ответ

0 голосов
/ 24 октября 2018

Вот еще один способ сделать это:

1) Использование NOT IN

Вы добавляете условие на usertable.user_id, которое не должно быть всписок идентификаторов: все эти идентификаторы являются идентификаторами таблицы friendrequests и friends, которые имеют to_id или from_id = 100.

SELECT 
  usertable.name,
  usertable.user_id,
  usertable.image
FROM `UserTable` AS usertable
WHERE usertable.user_id <> '100'
  AND usertable.user_id NOT IN 
    (SELECT from_id as user_id FROM friendrequests WHERE to_id = '100'
     UNION
     SELECT to_id as user_id FROM friendrequests WHERE from_id = '100'
     UNION
     SELECT from_id as user_id FROM friends WHERE to_id = '100'
     UNION
     SELECT to_id as user_id FROM friends WHERE from_id = '100')               
ORDER  BY usertable.joining_date DESC
LIMIT  10  

РЕДАКТИРОВАТЬ в соответствиина комментарий Рика Джеймса, то же самое без объединения:

SELECT 
  usertable.name,
  usertable.user_id,
  usertable.image
FROM `UserTable` AS usertable
WHERE usertable.user_id <> '100'
  AND usertable.user_id NOT IN (SELECT from_id as user_id FROM friendrequests WHERE to_id = '100')
  AND usertable.user_id NOT IN (SELECT to_id as user_id FROM friendrequests WHERE from_id = '100')
  AND usertable.user_id NOT IN (SELECT from_id as user_id FROM friends WHERE to_id = '100')
  AND usertable.user_id NOT IN (SELECT to_id as user_id FROM friends WHERE from_id = '100')               
ORDER  BY usertable.joining_date DESC
LIMIT  10  

2) Используя LEFT JOIN

Я видел этот ответ и пыталсяиспользовать ту же логику: вы создаете LEFT JOIN с другой таблицей и добавляете условие, при котором эти объединения возвращают значение NULL

SELECT 
  usertable.name,
  usertable.user_id,
  usertable.image
FROM `UserTable` AS usertable
LEFT JOIN friendrequests as FRa on FRa.from_id = usertable_user_id
LEFT JOIN friendrequests as FRb on FRb.to_id   = usertable_user_id
LEFT JOIN friends        as Fa  on Fa.from_id  = usertable_user_id
LEFT JOIN friends        as Fb  on Fb.to_id    = usertable_user_id
WHERE usertable.user_id <> '100' 
  AND FRa.from_id IS NULL
  AND FRb.to_id IS NULL
  AND Fa.from_id IS NULL
  AND Fb.to_id IS NULL

3) Использование NOT EXISTS

SELECT 
  usertable.name,
  usertable.user_id,
  usertable.image
FROM `UserTable` AS usertable
WHERE usertable.user_id <> '100'
  AND NOT EXISTS (SELECT from_id as user_id FROM friendrequests WHERE to_id = '100')
  AND NOT EXISTS (SELECT to_id as user_id FROM friendrequests WHERE from_id = '100')
  AND NOT EXISTS (SELECT from_id as user_id FROM friends WHERE to_id = '100')
  AND NOT EXISTS (SELECT to_id as user_id FROM friends WHERE from_id = '100')               
ORDER  BY usertable.joining_date DESC
LIMIT  10  

Извините, но без примеров данных или SQL Fiddle для проверки этого запроса, я не могу сказать вам, вернет ли он то, что вы хотите, или он действительно быстрее ...


РЕДАКТИРОВАТЬ : Эта страница с 2009 года, поэтому с тех пор результат изменился!Я не буду стирать его, поскольку у вас все еще есть структура запросов, которую я использовал ранее:

Я рекомендую вам просмотреть эту страницу, чтобы понять разницу между этими запросами и дать вам представление о том, чего вы хотите: https://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/

На этой странице предлагается третий способ (с использованием NOT EXISTS), но согласно тесту он неэффективен:

Этот запрос, однако, немного менее эффективенпо сравнению с предыдущими двумя: это занимает 0,92 с.

Это не очень значительное снижение производительности, однако запрос занимает на 27% больше времени.

...