У меня есть следующий запрос на dune.com:
SELECT
th.value / 1e18 as amount,
tr.success,
th."from",
th.to,
tr.hash,
tr.data,
FROM
table1 tr
table2 th ON tr.hash = th.evt_hash
WHERE
th.to = sjhd21
AND tr.success = true
AND (
th.value / 1e18 > 10
OR th."from" = h123g
)
AND CAST(tr.data AS varchar) NOT LIKE '0xbc4b3365%'
AND CAST(tr.data AS varchar) NOT LIKE '0x447e346f%'
AND CAST(tr.data AS varchar) NOT LIKE '0x0100670b%'
AND CAST(tr.data AS varchar) NOT LIKE '0x2d1fb389%'
AND CAST(tr.data AS varchar) NOT LIKE '0xb9181611%'
AND CAST(tr.data AS varchar) NOT LIKE '0x47e7ef24%'
AND CAST(tr.data AS varchar) NOT LIKE '0xdb6b5246%'
AND CAST(tr.data AS varchar) NOT LIKE '0xf80dec97%'
AND CAST(tr.data AS varchar) NOT LIKE '0x8129fc1c%'
AND CAST(tr.data AS varchar) NOT LIKE '0x8da5cb5b%'
AND CAST(tr.data AS varchar) NOT LIKE '0x7729d644%'
AND CAST(tr.data AS varchar) NOT LIKE '0xd6c9b6a5%'
AND CAST(tr.data AS varchar) NOT LIKE '0x143531c0%'
AND CAST(tr.data AS varchar) NOT LIKE '0x715018a6%'
AND CAST(tr.data AS varchar) NOT LIKE '0x4fb2e45d%'
AND CAST(tr.data AS varchar) NOT LIKE '0xf2fde38b%'
AND CAST(tr.data AS varchar) NOT LIKE '0x4f065632%'
AND CAST(tr.data AS varchar) NOT LIKE '0x7a78b9c7%'
AND CAST(tr.data AS varchar) NOT LIKE '0x535b355c%'
AND CAST(tr.data AS varchar) NOT LIKE '0x9c66c25d%'
Обработка этого запроса занимает много времени. Я предполагаю, что это потому, что я конвертирую столбец данных в предложении WHERE
.
Если я не конвертирую его, я получаю эту ошибку:
Левая часть выражения LIKE должна иметь значение varchar (фактически: varbinary).
Я пробовал использовать CTE для преобразования данных, но это все равно занимает столько же времени, поэтому я отказался от этого.
Какая альтернатива этому? Есть ли выражение, которое будет работать с данными как с varbinary?
Приведение левого аргумента (нет) like
вполне вероятно является причиной медленности, особенно если этот столбец проиндексирован.
Глядя на имеющиеся у вас условия, вы на самом деле не используете всю мощь оператора like
, а используете его только для проверки префикса. Более эффективно это можно сделать с помощью функции varbinary_starts_with:
AND NOT varbinary_starts_with(tr.data, 0xbc4b3365)
-- etc...
AND CAST(tr.data AS varchar) NOT LIKE '0xb9181611%'
Если это по сути числа, можете ли вы это сделать? AND NOT ( tr.data > 3105363473 and tr.data < 3105363474 )
Рассматривайте их как числа или сохраните версию числа, чтобы вы могли делать большее/меньше чем.
@PaulManley это сработает, только если вы что-то знаете о длине значения. В запросе ОП и в моем решении условие будет соответствовать таким значениям, как 0xbc4b336511111111
. С вашим решением этого не произойдет.
@Mureinik Не знаю насчет Дюны, но многие СУБД позволяют это сделать AND NOT (tr.data > 0xbc4b3365 AND tr.data < 0xbc4b3366)
Я не использую dune, но похоже, что вы просматриваете только первые 4 байта, поэтому у меня должна быть возможность использовать varbinary_substring и
not in