Remove usages of FIND_IN_SET

FIND_IN_SET doesn't make use of indexes
This commit is contained in:
jude
2024-10-10 19:06:56 +01:00
parent 137ae6f24b
commit 6f223b1bc2
7 changed files with 163 additions and 156 deletions

View File

@ -72,55 +72,60 @@ pub async fn get_reminders(
match channels_res {
Ok(channels) => {
let channels = channels
.keys()
.into_iter()
.map(|k| k.get().to_string())
.collect::<Vec<String>>()
.join(",");
let channels =
channels.keys().into_iter().map(|k| k.get().to_string()).collect::<Vec<String>>();
sqlx::query_as_unchecked!(
GetReminder,
let placeholder = vec!["?"; channels.len()].join(",");
let sql = format!(
"
SELECT
reminders.attachment_name,
reminders.avatar,
channels.channel,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
reminders.embed_color,
reminders.embed_description,
reminders.embed_footer,
reminders.embed_footer_url,
reminders.embed_image_url,
reminders.embed_thumbnail_url,
reminders.embed_title,
IFNULL(reminders.embed_fields, '[]') AS embed_fields,
reminders.enabled,
reminders.expires,
reminders.interval_seconds,
reminders.interval_days,
reminders.interval_months,
reminders.name,
reminders.restartable,
reminders.tts,
reminders.uid,
reminders.username,
reminders.utc_time
reminders.attachment_name,
reminders.avatar,
channels.channel,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
reminders.embed_color,
reminders.embed_description,
reminders.embed_footer,
reminders.embed_footer_url,
reminders.embed_image_url,
reminders.embed_thumbnail_url,
reminders.embed_title,
IFNULL(reminders.embed_fields, '[]') AS embed_fields,
reminders.enabled,
reminders.expires,
reminders.interval_seconds,
reminders.interval_days,
reminders.interval_months,
reminders.name,
reminders.restartable,
reminders.tts,
reminders.uid,
reminders.username,
reminders.utc_time
FROM reminders
INNER JOIN channels ON channels.id = reminders.channel_id
WHERE `status` = 'pending' AND FIND_IN_SET(channels.channel, ?)",
channels
)
.fetch_all(pool.inner())
.await
.map(|r| Ok(json!(r)))
.unwrap_or_else(|e| {
warn!("Failed to complete SQL query: {:?}", e);
INNER JOIN channels
ON channels.id = reminders.channel_id
WHERE `status` = 'pending'
AND channels.channel IN ({placeholder})
"
);
json_err!("Could not load reminders")
})
let mut query = sqlx::query_as::<Database, GetReminder>(&sql);
for channel in channels {
query = query.bind(channel);
}
query
.fetch_all(pool.inner())
.await
.map(|reminders| Ok(json!(reminders)))
.unwrap_or_else(|e| {
warn!("Failed to complete SQL query: {:?}", e);
json_err!("Could not load reminders")
})
}
Err(e) => {
warn!("Could not fetch channels from {}: {:?}", id, e);

View File

@ -1,3 +1,14 @@
use crate::web::{
check_authorization,
guards::transaction::Transaction,
routes::{
dashboard::{
create_reminder, CreateReminder, ImportBody, ReminderCsv, ReminderTemplateCsv, TodoCsv,
},
JsonResult,
},
};
use crate::Database;
use base64::{prelude::BASE64_STANDARD, Engine};
use csv::{QuoteStyle, WriterBuilder};
use log::warn;
@ -14,17 +25,6 @@ use serenity::{
};
use sqlx::{MySql, Pool};
use crate::web::{
check_authorization,
guards::transaction::Transaction,
routes::{
dashboard::{
create_reminder, CreateReminder, ImportBody, ReminderCsv, ReminderTemplateCsv, TodoCsv,
},
JsonResult,
},
};
#[get("/api/guild/<id>/export/reminders")]
pub async fn export_reminders(
id: u64,
@ -40,48 +40,47 @@ pub async fn export_reminders(
match channels_res {
Ok(channels) => {
let channels = channels
.keys()
.into_iter()
.map(|k| k.get().to_string())
.collect::<Vec<String>>()
.join(",");
let result = sqlx::query_as_unchecked!(
ReminderCsv,
"SELECT
reminders.attachment,
reminders.attachment_name,
reminders.avatar,
CONCAT('#', channels.channel) AS channel,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
reminders.embed_color,
reminders.embed_description,
reminders.embed_footer,
reminders.embed_footer_url,
reminders.embed_image_url,
reminders.embed_thumbnail_url,
reminders.embed_title,
reminders.embed_fields,
reminders.enabled,
reminders.expires,
reminders.interval_seconds,
reminders.interval_days,
reminders.interval_months,
reminders.name,
reminders.restartable,
reminders.tts,
reminders.username,
reminders.utc_time
let channels =
channels.keys().into_iter().map(|k| k.get().to_string()).collect::<Vec<String>>();
let placeholder = vec!["?"; channels.len()].join(",");
let sql = format!(
"
SELECT
reminders.attachment,
reminders.attachment_name,
reminders.avatar,
CONCAT('#', channels.channel) AS channel,
reminders.content,
reminders.embed_author,
reminders.embed_author_url,
reminders.embed_color,
reminders.embed_description,
reminders.embed_footer,
reminders.embed_footer_url,
reminders.embed_image_url,
reminders.embed_thumbnail_url,
reminders.embed_title,
reminders.embed_fields,
reminders.enabled,
reminders.expires,
reminders.interval_seconds,
reminders.interval_days,
reminders.interval_months,
reminders.name,
reminders.restartable,
reminders.tts,
reminders.username,
reminders.utc_time
FROM reminders
LEFT JOIN channels ON channels.id = reminders.channel_id
WHERE FIND_IN_SET(channels.channel, ?) AND status = 'pending'",
channels
)
.fetch_all(pool.inner())
.await;
LEFT JOIN channels
ON channels.id = reminders.channel_id
WHERE status = 'pending'
AND channels.channel IN ({placeholder})
"
);
let result =
sqlx::query_as::<Database, ReminderCsv>(&sql).fetch_all(pool.inner()).await;
match result {
Ok(reminders) => {

View File

@ -17,6 +17,7 @@ use serenity::{
model::id::{ChannelId, GuildId, UserId},
};
use sqlx::types::Json;
use sqlx::FromRow;
use crate::web::{
catchers::internal_server_error,
@ -177,7 +178,7 @@ pub struct CreateReminder {
utc_time: NaiveDateTime,
}
#[derive(Serialize)]
#[derive(Serialize, FromRow)]
pub struct GetReminder {
attachment_name: Option<String>,
avatar: Option<String>,
@ -209,7 +210,7 @@ pub struct GetReminder {
utc_time: NaiveDateTime,
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, FromRow)]
pub struct ReminderCsv {
attachment: Option<Attachment>,
attachment_name: Option<String>,