Вопросы по оптимизации медленного запроса (включая SQL) - PullRequest
1 голос
/ 01 июля 2011
SELECT DISTINCT "myapp_profile"."user_id", "myapp_profile"."name", 
  "myapp_profile"."age", "auth_user"."id", "auth_user"."username", 
  "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", 
  "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", 
  "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" 
FROM "myapp_profile" 
INNER JOIN "auth_user" ON ("myapp_profile"."user_id" = "auth_user"."id") 
LEFT OUTER JOIN "myapp_siterel" ON ("myapp_profile"."user_id" = "myapp_siterel"."profile_id") 
LEFT OUTER JOIN "django_site" ON ("myapp_siterel"."site_id" = "django_site"."id") 
WHERE ("auth_user"."is_superuser" = false 
AND "auth_user"."is_staff" = false 
AND ("django_site"."id" IS NULL OR "django_site"."id" IN (15, 16))) 
ORDER BY "myapp_profile"."user_id" 
DESC LIMIT 100

Приведенный выше запрос занимает около 100 секунд для выполнения с 2 миллионами пользователей / профилей.Я не администратор баз данных, и наши администраторы баз данных смотрят на ситуацию, чтобы увидеть, что можно сделать, но, поскольку я, вероятно, никогда не смогу увидеть, какие изменения (при условии, что это происходит на уровне базы данных), мне любопытно, как вы могли оптимизироватьэтот запрос.Очевидно, что это должно произойти на тонну быстрее, чем это происходит, примерно на 5 секунд или меньше.Если нет способа оптимизировать SQL, есть ли индекс или индексы, которые можно добавить / изменить, чтобы сделать запрос более быстрым, или есть что-то еще, что я пропускаю?

Postgres 9 - это БДи ORM Django - это источник этого запроса.

План запроса

Limit (cost=1374.35..1383.10 rows=100 width=106)
-> Unique (cost=1374.35..1391.24 rows=193 width=106)
-> Sort (cost=1374.35..1374.83 rows=193 width=106)
Sort Key: myapp_profile.user_id, myapp_profile.name, myapp_profile.age, auth_user.username, auth_user.first_name, auth_user.last_name, auth_user.email, auth_user.password, auth_user.is_staff, auth_user.is_active, auth_user.is_superuser, auth_user.last_login, auth_user.date_joined
-> Nested Loop (cost=453.99..1367.02 rows=193 width=106)
-> Hash Left Join (cost=453.99..1302.53 rows=193 width=49)
Hash Cond: (myapp_siterel.site_id = django_site.id)
Filter: ((django_site.id IS NULL) OR (django_site.id = ANY ('{10080,10053}'::integer[])))
-> Hash Left Join (cost=448.50..1053.27 rows=15001 width=53)
Hash Cond: (myapp_profile.user_id = myapp_siterel.profile_id)
-> Seq Scan on myapp_profile (cost=0.00..286.01 rows=15001 width=49)
-> Hash (cost=261.00..261.00 rows=15000 width=8)
-> Seq Scan on myapp_siterel (cost=0.00..261.00 rows=15000 width=8)
-> Hash (cost=3.55..3.55 rows=155 width=4)
-> Seq Scan on django_site (cost=0.00..3.55 rows=155 width=4)
-> Index Scan using auth_user_pkey on auth_user (cost=0.00..0.32 rows=1 width=57)
Index Cond: (auth_user.id = myapp_profile.user_id)
Filter: ((NOT auth_user.is_superuser) AND (NOT auth_user.is_staff))

Спасибо

Ответы [ 3 ]

2 голосов
/ 01 июля 2011

Я не очень знаком с postgres, поэтому я не уверен, насколько хорош его оптимизатор запросов, но похоже, что все, что есть в предложении where, может вместо этого быть условиями соединения, хотя я надеюсь, что postgres умный этого достаточно, чтобы разобраться в этом самому, однако, если это не так, он соберет всех ваших 2 миллионов пользователей со связанными записями в других 3 таблицах, а затем отфильтрует это, используя ваше где.

Уже упомянутые индексы также должны работать для вас, если они еще не существуют. Опять же, я более MSSQL, но разве у postgres нет профиля статистики или плана запросов, которые вы можете увидеть?

Что-то в этом роде

SELECT DISTINCT
    "myapp_profile"."user_id",
    "myapp_profile"."name", 
    "myapp_profile"."age",
    "auth_user"."id",
    "auth_user"."username", 
    "auth_user"."first_name",
    "auth_user"."last_name",
    "auth_user"."email", 
    "auth_user"."password",
    "auth_user"."is_staff",
    "auth_user"."is_active", 
    "auth_user"."is_superuser",
    "auth_user"."last_login",
    "auth_user"."date_joined" 
FROM "myapp_profile" 
    INNER JOIN "auth_user"
        ON ("myapp_profile"."user_id" = "auth_user"."id") 
        AND "auth_user"."is_superuser" = false
        AND "auth_user"."is_staff" = false 
    LEFT OUTER JOIN "myapp_siterel"
        ON ("myapp_profile"."user_id" = "myapp_siterel"."profile_id") 
    LEFT OUTER JOIN "django_site"
        ON ("myapp_siterel"."site_id" = "django_site"."id") 
        AND ("django_site"."id" IS NULL OR "django_site"."id" IN (15, 16))
ORDER BY "myapp_profile"."user_id" DESC
LIMIT 100

Кроме того, вам нужно отличное? Это также немного замедлит его.

1 голос
/ 01 июля 2011

никогда не бывает простого решения для оптимизации запросов, однако очевидными шагами является индексирование столбцов, по которым вы ведете поиск, в вашем случае это:

1 голос
/ 01 июля 2011

для основ:

убедитесь, что все поля идентификатора пользователя проиндексированы.

также выглядит так, как будто вы преуспели бы с индексом is_supervisor и is_staff

...