Как выполнить несколько задач SQL при использовании SQL внутри кода (в данном случае vbscript) - PullRequest
2 голосов
/ 03 октября 2010

Я бью кирпичную стену чем-то, что пытаюсь сделать.

Я пытаюсь выполнить сложный запрос и вернуть результаты в набор записей vbscript (vbs).

Чтобы ускорить запрос, я создаю временные таблицы и затем использую эти таблицы в основном запросе (создает увеличение скорости примерно на 1200% только при использовании подзапросов)

проблема в том, что внешний кодкажется, игнорирует основной запрос, только «видит» результат самой первой команды (то есть возвращает «затронутые записи»)

Например, для такого запроса, как этот ..

delete from temp
select * into temp from sometable where somefield = somefilter

select sum(someotherfield) from yetanothertable where account in (select * from temp)

Внешний код только «видит» возвращенный результат «delete from temp». Я не могу получить доступ к данным, которые возвращает третья команда.

(Очевидно, SQL-запрос вышепсевдо / фальшивка. реальный запрос большой и его содержание не имеет отношения к задаваемому вопросу. Мне нужно решить эту проблему, так как без возможности использовать временную таблицу запрос выполняется от 3 секунд до 6 минутutes!)

edit: я знаю, что смогу обойти это, сделав несколько вызовов ADODB.Connection выполнить (сделать вызов, чтобы очистить временные таблицы, сделать вызов, чтобы создать их снова, наконец, сделать вызовполучить данные), но я бы предпочел найти элегантное решение / способ избежать этого.

edit 2: Ниже приведен фактический код SQL, с которым я закончил.Просто добавляю это для любопытства людей, которые ответили.Он не использует nocount, так как я уже выбрал решение, которое работает для меня.Это также, вероятно, плохо написано.Со временем оно превратилось из чего-то более простого.Возможно, я мог бы улучшить его сам, но, поскольку он работает и возвращает данные очень быстро, я застрял с ним.(на данный момент)

Вот SQL.

SQL code screenshot

Вот код, где он вызывается.Мое выбранное решение состоит в том, чтобы выполнить первый запрос в третьей временной таблице, затем выполнить команду select * для этой таблицы из кода, а затем удалить из кода ...

VBS code screenshot

Я не претендую на то, чтобы быть «хорошим» сценарием sql (в основном самообучаемым через necesity), а база данных не очень хорошо спроектирована (смесь старых и новых таблиц. Старые таблицы не реляционные и содержат числовые значения и значения датыхранится в виде строк)

Вот оригинальный (медленный) запрос ...

    select 
name,
program_name,
sum(handle) + sum(refund) as [Total Sales],
sum(refund) as Refunds,
sum(handle) as [Net Sales],
sum(credit - refund) as Payout,
cast(sum(comm) as money) as commission
from 

(select accountnumber,program_name,
cast(credit_amount as money) as credit,cast(refund_amt as money) as refund,handle, handle * (
(select commission from amtotecommissions 
where _date = a._date 
and pool_type = (case when a.pool_type in ('WP','WS','PS','WPS') then 'WN' else a.pool_type end)
and program_name = a.program_name) / 100) as comm

from amtoteaccountactivity a where _date = '@yy/@mm/@dd' and transaction_type = 'Bet'
and accountnumber not in ('5067788','5096272') /*just to speed the query up a bit. I know these accounts aren't included*/
) a,

ews_db.dbo.amtotetrack t
where (a.accountnumber in (select accountno from ews_db.dbo.get_all_customers where country = 'US')
or a.accountnumber in ('5122483','5092147'))
and t.our_code = a.program_name collate database_default
and t.tracktype = 2


group by name,program_name

Ответы [ 3 ]

1 голос
/ 03 октября 2010

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

Я думаю, что вам лучше всего делать это как хранимую процедуру и вызывать ее.

CREATE PROCEDURE get_Count 
@somefilter int
AS
delete from temp;
select * into temp from sometable where somefield = @somefilter;

select sum(someotherfield) from yetanothertable 
where account in (select * from temp);

Однако пример, позволяющий избежать использования метода IN через JOIN, вероятно, решит проблему производительности,Используйте EXPLAIN SELECT, чтобы увидеть, что происходит, и оптимизировать оттуда.Например, следующий

select sum(transactions.value) from transactions
inner join user on transactions.user=user.id where user.name='Some User'

намного быстрее, чем

select sum(transactions.value) from transactions
where user in (SELECT id from user where user.name='Some User')

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


Rev1

Принимая медленный отправленный SQL, кажется, что происходит полное сканирование таблицы, где SQL сообщает WHERE .. IN Например,

where (a.accountnumber in (select accountno from ews_db.dbo.get_all_customers))

. Вышеприведенное будет содержать множество записей, которые могут не потребоваться.Это вместе с другими вложенными выборками таблиц не позволяет оптимизатору извлекать только совпадающие записи, как это было бы в случае использования JOIN на внешнем уровне.

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

Я имею в виду это, если у вас есть типичная БД с клиентами, у которых ordersкоторые создают transactions, которые содержат items, тогда я начну с items и добавлю остальные детали с помощью объединений.

В качестве только пример Я предлагаю построитьзапрос больше похож на следующий:

select name,
  program_name,
  SUM(handle) + SUM(refund) AS [Total Sales],
  SUM(refund) AS Refunds,
  SUM(handle) AS [Net Sales],
  SUM(credit - refund) AS Payout,
  CAST(SUM(comm) AS money) AS commission,

FROM ews_db.dbo.get_all_customers AS cu
 INNER JOIN amtoteactivity AS a ON a.accoutnumber = cu.accountnumber
 INNER JOIN ews_db.dbo.amtotetrack AS track ON track.our_code = a.program_name
 INNER JOIN amtotecommissions AS commision ON co.program_name = a.program_name

WHERE customers.country='US'
  AND t.tracktype = 2
  AND a.transaction_type = 'Bet'
  AND a._date = ''@yy/@mm/@dd'
  AND a.program_name = co.program_name
  AND co.pool_type = (case when a.pool_type in ('WP','WS','PS','WPS') then 'WN' else a.pool_type end)

GROUP BY name,program_name,co.commission

ПРИМЕЧАНИЕ : Выше не работает и для иллюстрации.Мне нужно иметь базу данных онлайн, чтобы построить реальный запрос.Я надеюсь, что вы поймете общую идею и создадите ее.

Мой главный совет для сложных запросов, которые не работают, - просто полностью начать снова отбрасывать то, что у вас уже есть.Иногда я делаю это три или четыре раза при создании действительно сложного запроса.

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

0 голосов
/ 03 марта 2016

Я только что решил свою первоначальную проблему (с которой сегодня снова столкнулся по другому запросу) немного хакерским способом ...

Conn.Execute(split(query,";")(0))
set rs = Conn.Execute(split(query,";")(1))

Отлично работает!

Редактировать : Я только что заметил, что первый комментарий к моему первоначальному вопросу также дал быстрое решение (set nocount on). Я забыл об этом. Ну, есть то и это. Я пытался заставить запрос работать без временной таблицы, но я не мог достичь такой же производительности, как с ней.

0 голосов
/ 03 октября 2010

Если бы вы могли прийти к общей структуре данных для всех селекторов, вы могли бы ОБЪЕДИНИТЬ ВСЕ их вместе, возможно, выбрав константу в каждом объединении, чтобы вы знали, откуда поступали данные - вроде

select '1',col1,col2,'' from table 1
UNION ALL
select '2',col1,col2,col3 from table2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...