Remove usages of FIND_IN_SET
FIND_IN_SET doesn't make use of indexes
This commit is contained in:
parent
137ae6f24b
commit
6f223b1bc2
@ -31,31 +31,33 @@ impl Recordable for Options {
|
||||
.filter(|(_, channel)| channel.is_text_based())
|
||||
.map(|(id, _)| id.get().to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
}) {
|
||||
sqlx::query!(
|
||||
let placeholder = vec!["?"; channels.len()].join(",");
|
||||
let sql = format!(
|
||||
"
|
||||
UPDATE reminders
|
||||
INNER JOIN `channels`
|
||||
ON `channels`.id = reminders.channel_id
|
||||
SET reminders.`utc_time` = DATE_ADD(reminders.`utc_time`, INTERVAL ? SECOND)
|
||||
WHERE FIND_IN_SET(channels.`channel`, ?)
|
||||
",
|
||||
combined_time as i64,
|
||||
channels
|
||||
)
|
||||
.execute(&ctx.data().database)
|
||||
.await
|
||||
.unwrap();
|
||||
UPDATE reminders
|
||||
INNER JOIN `channels`
|
||||
ON `channels`.id = reminders.channel_id
|
||||
SET reminders.`utc_time` = DATE_ADD(reminders.`utc_time`, INTERVAL ? SECOND)
|
||||
WHERE channels.`channel` IN ({placeholder})
|
||||
"
|
||||
);
|
||||
|
||||
let mut query = sqlx::query(&sql).bind(combined_time);
|
||||
for channel in channels {
|
||||
query = query.bind(channel);
|
||||
}
|
||||
|
||||
query.execute(&ctx.data().database).await.unwrap();
|
||||
} else {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE reminders
|
||||
INNER JOIN `channels`
|
||||
ON `channels`.id = reminders.channel_id
|
||||
SET reminders.`utc_time` = reminders.`utc_time` + ?
|
||||
WHERE channels.`channel` = ?
|
||||
",
|
||||
UPDATE reminders
|
||||
INNER JOIN `channels`
|
||||
ON `channels`.id = reminders.channel_id
|
||||
SET reminders.`utc_time` = reminders.`utc_time` + ?
|
||||
WHERE channels.`channel` = ?
|
||||
",
|
||||
combined_time as i64,
|
||||
ctx.channel_id().get()
|
||||
)
|
||||
|
@ -153,12 +153,12 @@ impl ComponentDataModel {
|
||||
ComponentDataModel::DelSelector(selector) => {
|
||||
if let ComponentInteractionDataKind::StringSelect { values } = &component.data.kind
|
||||
{
|
||||
let placeholder = values.iter().map(|_| "?").collect::<Vec<&str>>().join(",");
|
||||
let placeholder = vec!["?"; values.len()].join(",");
|
||||
let sql = format!(
|
||||
"UPDATE reminders SET `status` = 'deleted' WHERE id IN ({placeholder})"
|
||||
);
|
||||
let mut query = sqlx::query(&sql);
|
||||
|
||||
let mut query = sqlx::query(&sql);
|
||||
for id in values {
|
||||
query = query.bind(id);
|
||||
}
|
||||
@ -269,17 +269,15 @@ impl ComponentDataModel {
|
||||
if let ComponentInteractionDataKind::StringSelect { values } =
|
||||
&component.data.kind
|
||||
{
|
||||
let selected_id = values.join(",");
|
||||
let placeholder = vec!["?"; values.len()].join(",");
|
||||
let sql = format!("DELETE FROM todos WHERE id IN ({placeholder})");
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM todos WHERE FIND_IN_SET(id, ?)
|
||||
",
|
||||
selected_id
|
||||
)
|
||||
.execute(&data.database)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut query = sqlx::query(&sql);
|
||||
for id in values {
|
||||
query = query.bind(id);
|
||||
}
|
||||
|
||||
query.execute(&data.database).await.unwrap();
|
||||
|
||||
let values = if let Some(uid) = selector.user_id {
|
||||
sqlx::query!(
|
||||
|
@ -8,17 +8,6 @@ use std::{
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use chrono_tz::Tz;
|
||||
use poise::{
|
||||
serenity_prelude::{
|
||||
model::id::{ChannelId, GuildId, UserId},
|
||||
ButtonStyle, Cache, ChannelType, CreateActionRow, CreateButton, CreateEmbed, ReactionType,
|
||||
},
|
||||
CreateReply,
|
||||
};
|
||||
use sqlx::Executor;
|
||||
|
||||
use crate::{
|
||||
commands::look::{LookFlags, TimeDisplayType},
|
||||
component_models::{ComponentDataModel, UndoReminder},
|
||||
@ -36,8 +25,18 @@ use crate::{
|
||||
utils::{check_guild_subscription, check_subscription},
|
||||
Context, Database, Error,
|
||||
};
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use chrono_tz::Tz;
|
||||
use poise::{
|
||||
serenity_prelude::{
|
||||
model::id::{ChannelId, GuildId, UserId},
|
||||
ButtonStyle, Cache, ChannelType, CreateActionRow, CreateButton, CreateEmbed, ReactionType,
|
||||
},
|
||||
CreateReply,
|
||||
};
|
||||
use sqlx::{Executor, FromRow};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Reminder {
|
||||
pub id: u32,
|
||||
@ -140,7 +139,7 @@ impl Reminder {
|
||||
channel_id: C,
|
||||
flags: &LookFlags,
|
||||
) -> Vec<Self> {
|
||||
let enabled = if flags.show_disabled { "0,1" } else { "1" };
|
||||
let enabled = if flags.show_disabled { "0" } else { "1" };
|
||||
let channel_id = channel_id.into();
|
||||
|
||||
sqlx::query_as_unchecked!(
|
||||
@ -168,7 +167,7 @@ impl Reminder {
|
||||
WHERE
|
||||
`status` = 'pending' AND
|
||||
channels.channel = ? AND
|
||||
FIND_IN_SET(reminders.enabled, ?)
|
||||
reminders.enabled >= ?
|
||||
ORDER BY
|
||||
reminders.utc_time
|
||||
",
|
||||
@ -194,17 +193,16 @@ impl Reminder {
|
||||
.keys()
|
||||
.into_iter()
|
||||
.map(|k| k.get().to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(","),
|
||||
.collect::<Vec<String>>(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match channel_query {
|
||||
Some(channel_query) => {
|
||||
sqlx::query_as_unchecked!(
|
||||
Self,
|
||||
Some(channels) => {
|
||||
let placeholder = vec!["?"; channels.len()].join(",");
|
||||
let sql = format!(
|
||||
"
|
||||
SELECT
|
||||
reminders.id,
|
||||
@ -227,12 +225,16 @@ impl Reminder {
|
||||
channels.id = reminders.channel_id
|
||||
WHERE
|
||||
`status` = 'pending' AND
|
||||
FIND_IN_SET(channels.channel, ?)
|
||||
",
|
||||
channel_query
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
channels.channel IN ({placeholder})
|
||||
"
|
||||
);
|
||||
|
||||
let mut query = sqlx::query_as::<Database, Self>(&sql);
|
||||
for channel in channels {
|
||||
query = query.bind(channel);
|
||||
}
|
||||
|
||||
query.fetch_all(pool).await
|
||||
}
|
||||
None => {
|
||||
sqlx::query_as_unchecked!(
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -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>,
|
||||
|
@ -9,7 +9,7 @@ WorkingDirectory=/etc/reminder-rs
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment="RUST_LOG=warn,rocket=info,reminder_rs=debug,postman=debug"
|
||||
WatchdogSec=120
|
||||
WatchdogSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
Loading…
Reference in New Issue
Block a user