Cloud Spanner использует вторичный индекс, когда он не должен
Существующий запрос, который выполнялся быстро с использованием первичного ключа, значительно замедлился (10 мс -> 8 с) без уведомления, поскольку вторичный индекс, созданный для другого варианта использования, теперь используется автоматически.
"Объяснение" Cloud-Spanner-Web-Query говорит мне, что используется вторичный индекс. Если я изменю порядок (только для целей тестирования) или предоставлю FORCE_INDEX, запрос снова будет быстрым.
Я могу "исправить" эту проблему, используя FORCE_INDEX=_BASE_TABLE, которая описана в документации по синтаксису запроса Cloud Spanner.
Мой вопрос: действительно ли я должен делать это для каждого запроса, чтобы избежать таких эффектов?
Это смешивает определение запроса с определением индекса, что не очень хорошо, ИМХО.
Таблица с первичным индексом:
CREATE TABLE change_history (
userId INT64 NOT NULL,
createdAtUnique INT64 NOT NULL,
itemId STRING(512) NOT NULL,
newValue FLOAT64 NOT NULL,
oldValue FLOAT64 NOT NULL,
) PRIMARY KEY (userId, itemId, createdAtUnique DESC)
Вторичный индекс:
CREATE INDEX ch_userid_createdatunique_all ON change_history (
userId,
createdAtUnique
) STORING (
newValue,
oldValue
)
Исходный запрос:
SELECT * FROM change_history WHERE
userId = 2563
AND itemId = "215414"
AND createdAtUnique >= 15385766670000000
AND createdAtUnique <= 15465254670000000 ORDER BY createdAtUnique
Я ожидал, что запрос будет продолжать использовать первичный ключ, для которого он был разработан.
Но, добавив вторичный индекс, запрос начал использовать этот вместо первичного ключа.
1 ответ
Оптимизатор запросов в этом случае решил выбрать индекс, потому что 1) он покрывает и 2) избегает сортировки в первоначальном плане, потому что индекс содержит createdAtUnique
в порядке возрастания сортировки, который является порядком сортировки, запрашиваемым в запросе. Однако, для вашего распространения данных это оказалось плохим выбором.
В целом, для запросов, которые были настроены вручную для получения определенного плана, который, как вы знаете, является оптимальным / хорошим, целесообразно использовать force_index
а также join_type
подсказки в запросе для защиты от редкого случая, когда оптимизатор может выбрать другой план.