The mv command is calling rename() internally, and rename within a single filesystem mountpoint is only changing the name entry (either in the same directory or moving the name from one directory to another).
However, in some cases rename() will return EXDEV ("cross device link error") to the caller, and in this case mv will fall back to make a copy of the file (or entire directory tree) at the new location and delete the file/directory at the old location afterward.
The most common reason for rename() returning EXDEV is because the source and target directory of the rename() call are in different filesystems, of possibly different mountpoints of the same filesystem.  If project quotas are in use (run "lsattr -p" on the source file/dir and target dir to check) and the source/target are using different project IDs, then EXDEV is also returned to userspace and it is up to mv to make a copy of the file/directory tree at the target and to change the projid to match the new parent.
The reason that different project IDs on the source and target directory trigger a copy instead of just updating the project ID directly in rename() is because this can become far too complex to handle atomically within the kernel, if there is a whole directory tree that needs the projid to be changed. There might be thousands or millions of files that need to be updated in this case.  That said, the projid update could be done directly within rename() when renaming a single file, but this is not yet implemented in the ext4 code.
If you know project IDs are involved, you can avoid the "fallback copy" of a large file or directory tree by "pre-changing" the project ID of the source file(s)/directory tree to match the target projid. Run "chattr -R -p <target_projid> " before using "mv", so that the source and target projid are the same, then rename() should work without returning EXDEV and will not trigger the copy.