sybase - не может использовать индекс, если строка не является жестко закодированной - PullRequest
2 голосов
/ 23 марта 2010

Я использую Sybase 12.5.3 (ASE) ; Я новичок в Sybase, хотя я довольно много работал с MSSQL. Я сталкиваюсь со сценарием, где хранимая процедура действительно очень медленная. Я проследил проблему до единственного stmt SELECT для относительно большой таблицы. Изменение этого оператора значительно повышает производительность процедуры (и ее обратное резко замедляет; это, безусловно, является причиной SELECT stmt).

-- Sybase optimizes and uses multi-column index... fast!<br>
SELECT ID,status,dateTime
FROM myTable
WHERE status in ('NEW','SENT')
ORDER BY ID

-- Sybase does not use index and does very slow table scan<br>
SELECT ID,status,dateTime
FROM myTable
WHERE status in (select status from allowableStatusValues)
ORDER BY ID

Приведенный выше код является адаптированной / упрощенной версией фактического кода. Обратите внимание, что я уже попробовал перекомпилировать процедуру, обновить статистику и т. Д.

Я понятия не имею, почему Sybase ASE выбирает индекс только тогда, когда строки жестко запрограммированы, и выбирает сканирование таблицы при выборе из другой таблицы. Кто-нибудь, пожалуйста, дайте мне подсказку, и спасибо заранее.

Ответы [ 6 ]

2 голосов
/ 23 октября 2010

1. Проблема здесь в плохом кодировании. В вашем выпуске плохой код и плохой дизайн таблиц являются главными причинами (98%), что оптимизатор принимает неправильные решения (эти два идут рука об руку, я не определил соотношение каждого из них). Оба:

    WHERE status IN ('NEW','SENT')

и

    WHERE status IN (SELECT status FROM allowableStatusValues)

некачественные, потому что в обоих случаях ASE создает рабочий стол для содержимого в скобках, чего можно легко избежать (и избежать всех вытекающих из этого проблем). Статистика рабочего стола невозможна, так как статистика по t.status или s.status отсутствует (AdamH верен в этом отношении), он правильно выбирает сканирование таблицы.

Подзапросы имеют свое место, но никогда не заменяют чистого (таблицы имеют отношение ). Исправления:

    WHERE status = "NEW" OR status = "SENT"

и

    FROM  myTable t,
          allowableStatusValues s
    WHERE t.status = s.status

2. Заявление

| Теперь вам не нужно добавлять индекс для получения статистики по столбцу, но это, вероятно, лучший способ.

неверно. Никогда не создавайте индексы, которые вы не будете использовать. Если вы хотите обновить статистику по столбцу, просто

    UPDATE STATISTICS myTable (status)

3. Важно обеспечить, чтобы у вас была текущая статистика по (a) всем проиндексированным столбцам и (b) всем столбцам соединения.

4.Да, SHOWPLAN не может заменить ни один сегмент кода, предназначенный для выпуска, и вдвойне любой код с сомнительной производительностью. Вы также можете SET NOEXEC ON, чтобы избежать исполнения, например. для больших наборов результатов.

2 голосов
/ 24 марта 2010

Подсказка индекса будет работать вокруг него, но, вероятно, это не решение проблемы.

Во-первых, я хотел бы знать, есть ли индекс на allowableStatusValues.status, если есть, то sybase будет иметь статистику наэто и будет иметь хорошее представление о количестве значений там.Если нет, то оптимизатор, вероятно, не будет иметь четкого представления о том, сколько различных значений может принимать Status.Затем нужно сделать предположение, что вы собираетесь извлечь почти все строки из myTable, и лучший способ сделать это - сканирование таблицы (если индекс покрытия отсутствует).

Теперь вы неНе нужно добавлять индекс для получения статистики по столбцу, но это, вероятно, лучший способ.

Если у вас есть индекс для allowableStatusValues.status, то я бы удивился, насколько хороши ваши статистические данные.Получите себе копию sp__optdiag .Вам, вероятно, также необходимо настроить значения «коэффициента настройки гистограммы» и «количества шагов гистограммы», их небольшое увеличение по умолчанию даст вам более подробную статистику, которая всегда помогает оптимизатору.

1 голос
/ 24 марта 2010

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

SELECT m.ID,m.status,m.dateTime 
FROM myTable m
JOIN allowableStatusValues a on m.status = a.status
ORDER BY ID 
0 голосов
/ 24 марта 2010

Гаррет, показав только упрощенный код, вы, вероятно, вычеркнули именно ту информацию, которая осветит источник проблемы.

Моим первым предположением будет несоответствие типов между allowableStatusValues.status и myTable.status. Однако это не единственная возможность. Как указывалось выше, полные планы запросов (с использованием флагов showplan и fmtonly), а также фактические определения таблиц и источник хранимых процедур, с гораздо большей вероятностью дадут полезный ответ.

0 голосов
/ 23 марта 2010

Удивительно, но использование индексной подсказки решает проблему (см. Строку (index myIndexName) ниже - переписанный / упрощенный код ниже:

-- using INDEX HINT
SELECT ID,status,dateTime 
FROM myTable (index myIndexName)
WHERE status in (select status from allowableStatusValues) 
ORDER BY ID 

Странно, что у меня есть , чтобы использовать эту технику, чтобы избежать сканирования таблицы, но вы идете.

0 голосов
/ 23 марта 2010

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

SET showplan ON
GO

-- query/procedure call goes here
SELECT id, status, datetime
FROM myTable
WHERE status IN('NEW','SENT')
ORDER BY id
GO

SET showplan OFF
GO

При SET showplan ON Sybase генерирует планы выполнения для каждого выполняемого оператора. Они могут быть неоценимыми, помогая определить, где запросы не используют соответствующие индексы. Для хранимых процедур в Sybase план выполнения всей процедуры генерируется при первом запуске хранимой процедуры после компиляции.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...