简体   繁体   English

接受查询作为参数的存储过程

[英]Stored procedure that accepts a query as parameter

I'm trying to write a MySQL stored procedure that accepts a SELECT query and executes it against a list of databases. 我正在尝试编写一个MySQL存储过程,该存储过程接受SELECT查询并针对数据库列表执行它。 Is this even possible with MySQL? MySQL甚至有可能吗?

Each customer in our application has their own database on the same instance. 我们应用程序中的每个客户在同一实例上都有自己的数据库。 All customer databases are identical in their schema structure. 所有客户数据库的架构结构都相同。 Sometimes, I need to execute a simple SELECT query but across all the customer databases (eg SELECT COUNT(*) FROM users ). 有时,我需要在所有客户数据库中执行一个简单的SELECT查询(例如SELECT COUNT(*) FROM users )。

I have stored procedures for the common recurring "instance-wide" queries like the user count but I don't want to create more of those for one-time queries (eg querying for corrupted records due to by buggy code, querying for columns that we are planning to deprecate, etc.). 我已经为常见的重复“实例级”查询(例如用户计数)存储了存储过程,但我不想为一次性查询创建更多的存储过程(例如,由于错误代码而查询损坏的记录,查询那些我们打算弃用,等等。)

My current solution is that I have a node script that I run locally to generate SELECT queries for each database and then concatenate them all using UNION to generate a giant query that I then execute on the database instance. 我当前的解决方案是我有一个node脚本,该脚本在本地运行以为每个数据库生成SELECT查询,然后使用UNION将它们全部连接起来以生成一个大型查询,然后在数据库实例上执行该查询。

SELECT 'customerdb1' AS customer,
       COUNT(*) AS user_count
FROM customerdb1.users
UNION
SELECT 'customerdb2' AS customer,
       COUNT(*) AS user_count
FROM customerdb2.users
UNION
SELECT 'customerdb3' AS customer,
       COUNT(*) AS user_count
FROM customerdb3.users

You can do it in a stored procedure with PREPARE and EXECUTE , but it's considered a security vulnerability to run arbitrary SQL in this way. 您可以使用PREPARE和EXECUTE在存储过程中完成此操作,但是将其视为以这种方式运行任意SQL的安全漏洞。 You said the procedure would only be used by a special account, but just allowing the procedure to exist is a risk. 您说过,该程序只能由特殊帐户使用,但是仅允许该程序存在是一种风险。 What if privileges are modified and allow anyone to run the procedure? 如果修改了特权并允许任何人运行该程序怎么办?

It will also be pretty slow to run this query across many schemas, because MySQL only runs one thread per query. 在许多模式下运行该查询也将非常慢,因为MySQL每个查询只运行一个线程。 It will have to run the queries serially, collecting the result in a temp table. 它必须串行运行查询,并将结果收集到临时表中。

Also you have a limit on the length of any single SQL query, which is max_allowed_packet . 此外,您对任何单个SQL查询的长度都有一个限制,即max_allowed_packet This should be pretty large, but you can still exceed the length if you have enough UNION terms. 这应该非常大,但是如果您有足够的UNION术语,您仍然可以超过长度。

I worked on a site like the one you describe, where there were many schemas, one per customer, with identical tables. 我在一个您所描述的网站上工作,那里有许多模式,每个客户一个,具有相同的表。 When we wanted to run a query across all schemas, I would run a simple query (no UNION ) in many parallel threads, and collect the results in application code. 当我们想在所有架构上运行查询时,我将在多个并行线程中运行一个简单查询(不使用UNION ),并将结果收集到应用程序代码中。


See https://thedailywtf.com/articles/For-the-Ease-of-Maintenance for a fun story about stored procedures that allow input of arbitrary SQL. 有关允许输入任意SQL的存储过程的有趣故事,请参见https://thedailywtf.com/articles/For-the-Ease-of-Maintenance

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM