Проверьте значение, если оно существует в другой таблице в запросе Select

#sql #sql-server

Вопрос:

У меня есть три таблицы, в первой таблице хранится основная информация о пользователе, во второй таблице хранится информация о пользователе, существующем в каталоге LDAP, а в третьей таблице хранится общая информация обеих таблиц.

ниже приведена структура таблицы введите описание изображения здесь

Мне нужно имя из таблицы, если значение не совпадает, затем проверьте другую таблицу. желаемый результат выглядит следующим образом. Я пытался добиться этого, UNION но в таблице более 70 тысяч записей. это замедляет производительность. Запрос

 select Distinct
userInfoID AS 'UserInfoId',
accountName AS 'AccountName',
accountType AS 'AccountType',
privilege AS 'Privilege',
active AS 'IsActive',
org AS 'OrgName',
(L.firstName   ' '   L.lastName) AS 'Name',
emailId AS 'EmailAddress'
FROM tbl_UserInfo U
LEFT JOIN tbl_ldapUser L ON L.memberId = U.memberId

UNION

select Distinct
userInfoID AS 'UserInfoId',
accountName AS 'AccountName',
accountType AS 'AccountType',
privilege AS 'Privilege',
active AS 'IsActive',
org AS 'OrgName',
(M.firstName   ' '   M.lastName) AS 'Name',
emailId AS 'EmailAddress'
FROM tbl_UserInfo U
LEFT JOIN tbl_Member M ON M.memberId = U.memberId
 

введите описание изображения здесь

Комментарии:

1. Если запрос выполняется медленно, укажите его в своем вопросе.

2. Я подозреваю, что a NOT EXISTS будет более производительным по сравнению с a UNION , которому необходимо проверить, что 70k~ строк различны. Показав нам свою попытку, вы очень поможете нам помочь вам. Также необходимо не использовать изображения для текста.

3. @GordonLinoff я обновляю вопрос

4. Те DISTINCT s в SELECT s-это просто ненужные накладные расходы. Вы уже указываете, что набор данных должен быть DISTINCT связан с использованием вашего UNION .

5. Пожалуйста, поделитесь планом запроса через brentozar.com/pastetheplan . Полные определения индексов также помогли бы

Ответ №1:

Это невозможно проверить, однако я подозреваю, что это будет гораздо эффективнее. Во-первых , я меняю JOIN s на an INNER JOIN , а не на a LEFT JOIN . Если в строке in tbl_UserInfo не может быть совпадающих строк в обоих tbl_ldapUser и tbl_Member , и вы все еще хотите, чтобы эта строка возвращалась, измените нижний запрос на a LEFT JOIN (не верхний).

Я удаляю оба DISTINCT s, так как это просто дополнительные накладные расходы; вы использовали UNION , поэтому вы уже заявили механизму обработки данных, что вам нужны отдельные строки. Однако я также изменил значение UNION на a UNION ALL , что полностью удаляет предложение distinct; вероятно, поэтому ваш запрос был медленным , поскольку DISTINCT может быть очень дорогим оператором.

Наконец, я использую EXISTS вместо этого, чтобы проверить, существовала ли строка в tbl_ldapUser таблице в нижнем запросе. Это останавливает возврат пользователя дважды при сопоставлении с обеими таблицами:

 SELECT userInfoID AS UserInfoId,
       accountName AS AccountName,
       accountType AS AccountType,
       privilege AS Privilege,
       active AS IsActive,
       org AS OrgName,
       (L.firstName   ' '   L.lastName) AS [Name],
       emailId AS EmailAddress
FROM tbl_UserInfo U
     JOIN tbl_ldapUser L ON L.memberId = U.memberId
UNION ALL
SELECT userInfoID AS UserInfoId,
       accountName AS AccountName,
       accountType AS AccountType,
       privilege AS Privilege,
       active AS IsActive,
       org AS OrgName,
       (M.firstName   ' '   M.lastName) AS Name,
       emailId AS EmailAddress
FROM tbl_UserInfo U
     JOIN tbl_Member M ON M.memberId = U.memberId
WHERE NOT EXISTS (SELECT 1
                  FROM tbl_ldapUser L
                  WHERE L.memberId = U.memberId);
 

Также обратите внимание, что я удаляю одинарные кавычки вокруг псевдонимов. Это плохая привычка. Одинарные кавычки предназначены для буквенных строк и (даже если они поддерживаются) не должны использоваться для сглаживания. Чтение часто может сбивать с толку, и люди, незнакомые с языком, могут подумать, что синтаксис работает в другом месте. Например ORDER BY 'UserInfoId' , будет упорядочиваться не по столбцу, использующему псевдоним 'UserInfoId' , а по буквенной строке 'UserInfoId' ; это означает, что порядок полностью произвольный (так как каждая строка имеет одно и то же значение, 'UserInfoId' ).

Ответ №2:

Вы можете объединиться tbl_ldapUser , и tbl_Member перед присоединением это означает, что tbl_UserInfo запрос будет отправлен только один раз.

Кроме того, если между двумя таблицами нет дубликатов, вы можете перейти к тому UNION ALL , что будет быстрее.

 SELECT
  u.userInfoID AS UserInfoId,
  u.accountName AS AccountName,
  u.accountType AS AccountType,
  u.privilege AS Privilege,
  u.active AS IsActive,
  u.org AS OrgName,
  (l.firstName   ' '   l.lastName) AS [Name],
  l.emailId AS EmailAddress
FROM tbl_UserInfo U
JOIN (
    SELECT
        l.firstName,
        l.lastName,
        l.emailId,
        l.memberid
      FROM tbl_ldapUser l
    UNION ALL
-- if there could be duplicates between the two tables change to UNION
    SELECT
        m.firstName,
        m.lastName,
        m.emailId,
        m.memberid
      FROM tbl_Member m
) l ON l.memberId = u.memberId;