2017-02-23 43 views
1

Я не могу это понять.Почему запрос в результатах запроса дублирует записи

SELECT COUNT(*) FROM profiles 
WHERE profiles.status IN ('abc', 'man') 
    AND profiles.id IN (
         SELECT artifacts.item_id FROM artifacts 
         WHERE artifacts.deleted_at IS NULL 
          AND artifacts.item_type = 'Profile' 
          AND artifacts.upload_type = 'bill' 
        ); 
count 
------- 
12514 
(1 row) 

Вышеуказанный запрос подсчитывает повторяющиеся записи профилей (для которых артефакты имеют несколько записей). Когда я запускаю указанный выше запрос с помощью я получаю правильный счет, который ниже.

SELECT COUNT(DISTINCT(id)) FROM profiles 
WHERE profiles.status IN ('abc', 'man') 
    AND profiles.id IN (
         SELECT artifacts.item_id FROM artifacts 
         WHERE artifacts.deleted_at IS NULL 
          AND artifacts.item_type = 'Profile' 
          AND artifacts.upload_type = 'bill' 
        ); 
count 
------- 
12157 
(1 row) 

Артефакты могут иметь более одной записи для одного профиля. Но в соответствии с моим пониманием запрос IN не позволит ни одному дублируемому профилю войти в счет. Я прав? или есть что-то, чего я не хватает?

ОБНОВЛЕНИЕ:

Я пытался уменьшить запрос на 2-х различных условий фильтрации. Оба условия отлично работают. Пожалуйста, посмотрите ниже.

=> SELECT COUNT(*) FROM profiles WHERE profiles.id IN (
      SELECT artifacts.item_id FROM artifacts 
      WHERE artifacts.deleted_at IS NULL 
      AND artifacts.item_type = 'Profile' 
      AND artifacts.upload_type = 'bill'); 
count 
------- 
22664 
(1 row) 

=> SELECT COUNT(DISTINCT(id)) FROM profiles WHERE profiles.id IN (
      SELECT artifacts.item_id FROM artifacts 
      WHERE artifacts.deleted_at IS NULL 
      AND artifacts.item_type = 'Profile' 
      AND artifacts.upload_type = 'bill'); 
count 
------- 
22664 
(1 row) 


=> SELECT COUNT(DISTINCT(id)) FROM profiles 
     WHERE profiles.status IN ('abc', 'man'); 
count 
------- 
20109 
(1 row) 

=> SELECT COUNT(*) FROM profiles 
     WHERE profiles.status IN ('abc', 'man'); 
count 
------- 
20109 

Так дублирование происходит, когда два IN Использовано запросов в конъюнкции. Кто-нибудь знаком с таким вариантом использования.

+1

Вот глупый вопрос - у вас есть дубликаты идентификаторов в таблице профилей? – paqash

+0

@paqash Невозможно. Идентификатор - это первичный ключ. – dnsh

+0

попробуйте запустить 'SELECT id FROM profiles ... за исключением SELECT различных id FROM profiles..', чтобы получить список« not distinct id »? .. –

ответ

0

Есть две возможности:

  1. id не является уникальным в profiles.

    Вы можете выполнить следующий запрос, чтобы изучить этот вопрос:

    SELECT profiles.id, count(*) FROM profiles 
    WHERE profiles.status IN ('abc', 'man') 
        AND profiles.id IN (
             SELECT artifacts.item_id FROM artifacts 
             WHERE artifacts.deleted_at IS NULL 
              AND artifacts.item_type = 'Profile' 
              AND artifacts.upload_type = 'bill' 
            ) 
    GROUP BY profiles.id 
    HAVING count(*) > 1; 
    

    Это вернет id S, которые являются дубликатом.

    Вам не хватает UNIQUE или PRIMARY KEY ограничение по этой теме?

  2. Если есть UNIQUE или PRIMARY KEY ограничение на id, вы сталкиваетесь с повреждением данных. Посмотрите на план запроса – использует ли оно сканирование индексов или последовательное сканирование?

    Если установка enable_indexscan, enable_bitmapscan и enable_indexonlyscan - off устраняет проблему, у вас есть поврежденный индекс. REINDEX TABLE profiles, вероятно, устранит проблему.

    Если запрос также возвращает плохие результаты, если используются только последовательные проверки, вы сталкиваетесь с повреждением таблицы. Восстановите последнюю резервную копию.

    В любом случае, если это было повреждение данных, найдите причину и исправьте ее. Это может быть некорректная ОЗУ или хранилище, или сбои сервера в хранилище, которые должным образом не соблюдают запросы синхронизации. Прочтите журналы базы данных!